diff options
Diffstat (limited to 'drivers')
619 files changed, 12792 insertions, 6356 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 263e86ddc1a..f3946341890 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -14,6 +14,10 @@ source "drivers/pnp/Kconfig" source "drivers/block/Kconfig" +# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4 + +source "drivers/misc/Kconfig" + source "drivers/ide/Kconfig" source "drivers/scsi/Kconfig" @@ -52,8 +56,6 @@ source "drivers/w1/Kconfig" source "drivers/hwmon/Kconfig" -source "drivers/misc/Kconfig" - source "drivers/mfd/Kconfig" source "drivers/media/Kconfig" diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 98099de59b4..6bcd9e8e7bc 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -85,6 +85,8 @@ struct acpi_memory_device { struct list_head res_list; }; +static int acpi_hotmem_initialized; + static acpi_status acpi_memory_get_resource(struct acpi_resource *resource, void *context) { @@ -414,7 +416,7 @@ static int acpi_memory_device_add(struct acpi_device *device) /* Set the device state */ mem_device->state = MEMORY_POWER_ON_STATE; - printk(KERN_INFO "%s \n", acpi_device_name(device)); + printk(KERN_DEBUG "%s \n", acpi_device_name(device)); return result; } @@ -438,6 +440,15 @@ static int acpi_memory_device_start (struct acpi_device *device) struct acpi_memory_device *mem_device; int result = 0; + /* + * Early boot code has recognized memory area by EFI/E820. + * If DSDT shows these memory devices on boot, hotplug is not necessary + * for them. So, it just returns until completion of this driver's + * start up. + */ + if (!acpi_hotmem_initialized) + return 0; + mem_device = acpi_driver_data(device); if (!acpi_memory_check_device(mem_device)) { @@ -537,6 +548,7 @@ static int __init acpi_memory_device_init(void) return -ENODEV; } + acpi_hotmem_initialized = 1; return 0; } diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index e9ee4c52a5f..c7ac9297a20 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -138,6 +138,7 @@ struct asus_hotk { S2x, //S200 (J1 reported), Victor MP-XP7210 W1N, //W1000N W5A, //W5A + W3V, //W3030V xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N //(Centrino) END_MODEL @@ -376,6 +377,17 @@ static struct model_data model_conf[END_MODEL] = { .display_get = "\\ADVG"}, { + .name = "W3V", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\BKLT", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\INFB"}, + + { .name = "xxN", .mt_mled = "MLED", /* WLED present, but not controlled by ACPI */ @@ -555,11 +567,11 @@ static int write_led(const char __user * buffer, unsigned long count, char *ledname, int ledmask, int invert) { - int value; + int rv, value; int led_out = 0; - count = parse_arg(buffer, count, &value); - if (count > 0) + rv = parse_arg(buffer, count, &value); + if (rv > 0) led_out = value ? 1 : 0; hotk->status = @@ -572,7 +584,7 @@ write_led(const char __user * buffer, unsigned long count, printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n", ledname); - return count; + return rv; } /* @@ -607,20 +619,18 @@ static int proc_write_ledd(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) { + rv = parse_arg(buffer, count, &value); + if (rv > 0) { if (!write_acpi_int (hotk->handle, hotk->methods->mt_ledd, value, NULL)) printk(KERN_WARNING "Asus ACPI: LED display write failed\n"); else hotk->ledd_status = (u32) value; - } else if (count < 0) - printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); - - return count; + } + return rv; } /* @@ -761,12 +771,12 @@ static int proc_write_lcd(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) + rv = parse_arg(buffer, count, &value); + if (rv > 0) set_lcd_state(value); - return count; + return rv; } static int read_brightness(void) @@ -830,18 +840,15 @@ static int proc_write_brn(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) { + rv = parse_arg(buffer, count, &value); + if (rv > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ set_brightness(value); - } else if (count < 0) { - printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } - - return count; + return rv; } static void set_display(int value) @@ -880,15 +887,12 @@ static int proc_write_disp(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) + rv = parse_arg(buffer, count, &value); + if (rv > 0) set_display(value); - else if (count < 0) - printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); - - return count; + return rv; } typedef int (proc_readfunc) (char *page, char **start, off_t off, int count, @@ -1097,6 +1101,8 @@ static int asus_model_match(char *model) return A4G; else if (strncmp(model, "W1N", 3) == 0) return W1N; + else if (strncmp(model, "W3V", 3) == 0) + return W3V; else if (strncmp(model, "W5A", 3) == 0) return W5A; else @@ -1200,9 +1206,10 @@ static int asus_hotk_get_info(void) hotk->methods->mt_wled = NULL; /* L5D's WLED is not controlled by ACPI */ else if (strncmp(string, "M2N", 3) == 0 || + strncmp(string, "W3V", 3) == 0 || strncmp(string, "S1N", 3) == 0) hotk->methods->mt_wled = "WLED"; - /* M2N and S1N have a usable WLED */ + /* M2N, S1N and W3V have a usable WLED */ else if (asus_info) { if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) hotk->methods->mled_status = NULL; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9810e2a55d0..026e40755cd 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); static int acpi_battery_add(struct acpi_device *device); static int acpi_battery_remove(struct acpi_device *device, int type); +static int acpi_battery_resume(struct acpi_device *device, int status); static struct acpi_driver acpi_battery_driver = { .name = ACPI_BATTERY_DRIVER_NAME, @@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_driver = { .ids = ACPI_BATTERY_HID, .ops = { .add = acpi_battery_add, + .resume = acpi_battery_resume, .remove = acpi_battery_remove, }, }; @@ -753,6 +755,18 @@ static int acpi_battery_remove(struct acpi_device *device, int type) return 0; } +/* this is needed to learn about changes made in suspended state */ +static int acpi_battery_resume(struct acpi_device *device, int state) +{ + struct acpi_battery *battery; + + if (!device) + return -EINVAL; + + battery = device->driver_data; + return acpi_battery_check(battery); +} + static int __init acpi_battery_init(void) { int result; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e5d79636285..e6d4b084dca 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -45,206 +45,143 @@ ACPI_MODULE_NAME("acpi_ec") #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" + +/* EC status register */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ -#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ -#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ -#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ -#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ -#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ -#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ + +/* EC commands */ #define ACPI_EC_COMMAND_READ 0x80 #define ACPI_EC_COMMAND_WRITE 0x81 #define ACPI_EC_BURST_ENABLE 0x82 #define ACPI_EC_BURST_DISABLE 0x83 #define ACPI_EC_COMMAND_QUERY 0x84 -#define EC_POLL 0xFF -#define EC_INTR 0x00 + +/* EC events */ +enum { + ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ + ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ +}; + +#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ +#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ +#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ +#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ + +enum { + EC_INTR = 1, /* Output buffer full */ + EC_POLL, /* Input buffer empty */ +}; + static int acpi_ec_remove(struct acpi_device *device, int type); static int acpi_ec_start(struct acpi_device *device); static int acpi_ec_stop(struct acpi_device *device, int type); -static int acpi_ec_intr_add(struct acpi_device *device); -static int acpi_ec_poll_add(struct acpi_device *device); +static int acpi_ec_add(struct acpi_device *device); static struct acpi_driver acpi_ec_driver = { .name = ACPI_EC_DRIVER_NAME, .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { - .add = acpi_ec_intr_add, + .add = acpi_ec_add, .remove = acpi_ec_remove, .start = acpi_ec_start, .stop = acpi_ec_stop, }, }; -union acpi_ec { - struct { - u32 mode; - acpi_handle handle; - unsigned long uid; - unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; - unsigned long global_lock; - } common; - - struct { - u32 mode; - acpi_handle handle; - unsigned long uid; - unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; - unsigned long global_lock; - unsigned int expect_event; - atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ - atomic_t pending_gpe; - struct semaphore sem; - wait_queue_head_t wait; - } intr; - - struct { - u32 mode; - acpi_handle handle; - unsigned long uid; - unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; - unsigned long global_lock; - struct semaphore sem; - } poll; -}; -static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); -static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); -static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data); -static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data); -static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data); -static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data); -static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data); -static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data); -static void acpi_ec_gpe_poll_query(void *ec_cxt); -static void acpi_ec_gpe_intr_query(void *ec_cxt); -static u32 acpi_ec_gpe_poll_handler(void *data); -static u32 acpi_ec_gpe_intr_handler(void *data); -static acpi_status __init -acpi_fake_ecdt_poll_callback(acpi_handle handle, - u32 Level, void *context, void **retval); - -static acpi_status __init -acpi_fake_ecdt_intr_callback(acpi_handle handle, - u32 Level, void *context, void **retval); - -static int __init acpi_ec_poll_get_real_ecdt(void); -static int __init acpi_ec_intr_get_real_ecdt(void); /* If we find an EC via the ECDT, we need to keep a ptr to its context */ -static union acpi_ec *ec_ecdt; +struct acpi_ec { + acpi_handle handle; + unsigned long uid; + unsigned long gpe_bit; + unsigned long command_addr; + unsigned long data_addr; + unsigned long global_lock; + struct semaphore sem; + unsigned int expect_event; + atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ + wait_queue_head_t wait; +} *ec_ecdt; /* External interfaces use first EC only, so remember */ static struct acpi_device *first_ec; -static int acpi_ec_poll_mode = EC_INTR; +static int acpi_ec_mode = EC_INTR; /* -------------------------------------------------------------------------- Transaction Management -------------------------------------------------------------------------- */ -static u32 acpi_ec_read_status(union acpi_ec *ec) +static inline u8 acpi_ec_read_status(struct acpi_ec *ec) { - u32 status = 0; - - acpi_hw_low_level_read(8, &status, &ec->common.status_addr); - return status; + return inb(ec->command_addr); } -static int acpi_ec_wait(union acpi_ec *ec, u8 event) +static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { - if (acpi_ec_poll_mode) - return acpi_ec_poll_wait(ec, event); - else - return acpi_ec_intr_wait(ec, event); + return inb(ec->data_addr); } -static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event) +static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) { - u32 acpi_ec_status = 0; - u32 i = ACPI_EC_UDELAY_COUNT; + outb(command, ec->command_addr); +} - if (!ec) - return -EINVAL; +static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) +{ + outb(data, ec->data_addr); +} - /* Poll the EC status register waiting for the event to occur. */ +static int acpi_ec_check_status(u8 status, u8 event) +{ switch (event) { - case ACPI_EC_EVENT_OBF: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, - &ec->common.status_addr); - if (acpi_ec_status & ACPI_EC_FLAG_OBF) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i > 0); + case ACPI_EC_EVENT_OBF_1: + if (status & ACPI_EC_FLAG_OBF) + return 1; break; - case ACPI_EC_EVENT_IBE: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, - &ec->common.status_addr); - if (!(acpi_ec_status & ACPI_EC_FLAG_IBF)) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i > 0); + case ACPI_EC_EVENT_IBF_0: + if (!(status & ACPI_EC_FLAG_IBF)) + return 1; break; default: - return -EINVAL; + break; } - return -ETIME; + return 0; } -static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event) -{ - int result = 0; - - ec->intr.expect_event = event; - smp_mb(); +static int acpi_ec_wait(struct acpi_ec *ec, u8 event) +{ + int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0; + long time_left; - switch (event) { - case ACPI_EC_EVENT_IBE: - if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) { - ec->intr.expect_event = 0; - return 0; - } - break; - default: - break; + ec->expect_event = event; + if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { + ec->expect_event = 0; + return 0; } - result = wait_event_timeout(ec->intr.wait, - !ec->intr.expect_event, + do { + if (acpi_ec_mode == EC_POLL) { + udelay(ACPI_EC_UDELAY); + } else { + time_left = wait_event_timeout(ec->wait, + !ec->expect_event, msecs_to_jiffies(ACPI_EC_DELAY)); - - ec->intr.expect_event = 0; - smp_mb(); - - /* - * Verify that the event in question has actually happened by - * querying EC status. Do the check even if operation timed-out - * to make sure that we did not miss interrupt. - */ - switch (event) { - case ACPI_EC_EVENT_OBF: - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) + if (time_left > 0) { + ec->expect_event = 0; + return 0; + } + } + if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { + ec->expect_event = 0; return 0; - break; + } + } while (--i > 0); - case ACPI_EC_EVENT_IBE: - if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) - return 0; - break; - } + ec->expect_event = 0; return -ETIME; } @@ -254,272 +191,150 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event) * Note: samsung nv5000 doesn't work with ec burst mode. * http://bugzilla.kernel.org/show_bug.cgi?id=4980 */ -int acpi_ec_enter_burst_mode(union acpi_ec *ec) +int acpi_ec_enter_burst_mode(struct acpi_ec *ec) { - u32 tmp = 0; - int status = 0; + u8 tmp = 0; + u8 status = 0; status = acpi_ec_read_status(ec); if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (status) goto end; - acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr); + acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); + tmp = acpi_ec_read_data(ec); if (tmp != 0x90) { /* Burst ACK byte */ return -EINVAL; } } - atomic_set(&ec->intr.leaving_burst, 0); + atomic_set(&ec->leaving_burst, 0); return 0; - end: - ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode"); + end: + ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); return -1; } -int acpi_ec_leave_burst_mode(union acpi_ec *ec) +int acpi_ec_leave_burst_mode(struct acpi_ec *ec) { - int status = 0; + u8 status = 0; status = acpi_ec_read_status(ec); if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){ - status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if(status) goto end; - acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); - acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); - } - atomic_set(&ec->intr.leaving_burst, 1); + acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE); + acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); + } + atomic_set(&ec->leaving_burst, 1); return 0; -end: - ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"); + end: + ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode")); return -1; } #endif /* ACPI_FUTURE_USAGE */ -static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) -{ - if (acpi_ec_poll_mode) - return acpi_ec_poll_read(ec, address, data); - else - return acpi_ec_intr_read(ec, address, data); -} -static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data) -{ - if (acpi_ec_poll_mode) - return acpi_ec_poll_write(ec, address, data); - else - return acpi_ec_intr_write(ec, address, data); -} -static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - acpi_status status = AE_OK; - int result = 0; - u32 glk = 0; + int result; + acpi_ec_write_cmd(ec, command); - if (!ec || !data) - return -EINVAL; - - *data = 0; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; + for (; wdata_len > 0; wdata_len --) { + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); + if (result) + return result; + acpi_ec_write_data(ec, *(wdata++)); } - if (down_interruptible(&ec->poll.sem)) { - result = -ERESTARTSYS; - goto end_nosem; + if (command == ACPI_EC_COMMAND_WRITE) { + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); + if (result) + return result; } - - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, - &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) - goto end; - - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", - *data, address)); - - end: - up(&ec->poll.sem); -end_nosem: - if (ec->common.global_lock) - acpi_release_global_lock(glk); - - return result; -} - -static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data) -{ - int result = 0; - acpi_status status = AE_OK; - u32 glk = 0; + for (; rdata_len > 0; rdata_len --) { + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); + if (result) + return result; - if (!ec) - return -EINVAL; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } - - if (down_interruptible(&ec->poll.sem)) { - result = -ERESTARTSYS; - goto end_nosem; + *(rdata++) = acpi_ec_read_data(ec); } - - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, - &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - - acpi_hw_low_level_write(8, data, &ec->common.data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", - data, address)); - - end: - up(&ec->poll.sem); -end_nosem: - if (ec->common.global_lock) - acpi_release_global_lock(glk); - - return result; + return 0; } -static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - int status = 0; + int status; u32 glk; - - if (!ec || !data) + if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) return -EINVAL; - *data = 0; + if (rdata) + memset(rdata, 0, rdata_len); - if (ec->common.global_lock) { + if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) return -ENODEV; } + down(&ec->sem); - WARN_ON(in_interrupt()); - down(&ec->intr.sem); - - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (status) { printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); goto end; } - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); - } - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (status) { - printk(KERN_DEBUG PREFIX "read EC, OB not full\n"); - goto end; - } - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", - *data, address)); + status = acpi_ec_transaction_unlocked(ec, command, + wdata, wdata_len, + rdata, rdata_len); - end: - up(&ec->intr.sem); +end: + up(&ec->sem); - if (ec->common.global_lock) + if (ec->global_lock) acpi_release_global_lock(glk); return status; } -static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data) +static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) { - int status = 0; - u32 glk; - - - if (!ec) - return -EINVAL; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } - - WARN_ON(in_interrupt()); - down(&ec->intr.sem); - - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); - } - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); - } - - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); - } - - acpi_hw_low_level_write(8, data, &ec->common.data_addr); + int result; + u8 d; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", - data, address)); - - up(&ec->intr.sem); - - if (ec->common.global_lock) - acpi_release_global_lock(glk); + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, + &address, 1, &d, 1); + *data = d; + return result; +} - return status; +static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) +{ + u8 wdata[2] = { address, data }; + return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, + wdata, 2, NULL, 0); } /* * Externally callable EC access functions. For now, assume 1 EC only */ -int ec_read(u8 addr, u8 * val) +int ec_read(u8 addr, u8 *val) { - union acpi_ec *ec; + struct acpi_ec *ec; int err; - u32 temp_data; + u8 temp_data; if (!first_ec) return -ENODEV; @@ -539,7 +354,7 @@ EXPORT_SYMBOL(ec_read); int ec_write(u8 addr, u8 val) { - union acpi_ec *ec; + struct acpi_ec *ec; int err; if (!first_ec) @@ -554,255 +369,106 @@ int ec_write(u8 addr, u8 val) EXPORT_SYMBOL(ec_write); -static int acpi_ec_query(union acpi_ec *ec, u32 * data) -{ - if (acpi_ec_poll_mode) - return acpi_ec_poll_query(ec, data); - else - return acpi_ec_intr_query(ec, data); -} -static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data) +extern int ec_transaction(u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - int result = 0; - acpi_status status = AE_OK; - u32 glk = 0; - - - if (!ec || !data) - return -EINVAL; - - *data = 0; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } + struct acpi_ec *ec; - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - if (down_interruptible(&ec->poll.sem)) { - result = -ERESTARTSYS; - goto end_nosem; - } - - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, - &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) - goto end; - - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - if (!*data) - result = -ENODATA; + if (!first_ec) + return -ENODEV; - end: - up(&ec->poll.sem); -end_nosem: - if (ec->common.global_lock) - acpi_release_global_lock(glk); + ec = acpi_driver_data(first_ec); - return result; + return acpi_ec_transaction(ec, command, wdata, + wdata_len, rdata, rdata_len); } -static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data) -{ - int status = 0; - u32 glk; - - if (!ec || !data) - return -EINVAL; - *data = 0; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } +EXPORT_SYMBOL(ec_transaction); - down(&ec->intr.sem); +static int acpi_ec_query(struct acpi_ec *ec, u8 *data) +{ + int result; + u8 d; - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "query EC, IB not empty\n"); - goto end; - } - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (status) { - printk(KERN_DEBUG PREFIX "query EC, OB not full\n"); - goto end; - } + if (!ec || !data) + return -EINVAL; - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - if (!*data) - status = -ENODATA; + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ - end: - up(&ec->intr.sem); + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); + if (result) + return result; - if (ec->common.global_lock) - acpi_release_global_lock(glk); + if (!d) + return -ENODATA; - return status; + *data = d; + return 0; } /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ -union acpi_ec_query_data { +struct acpi_ec_query_data { acpi_handle handle; u8 data; }; static void acpi_ec_gpe_query(void *ec_cxt) { - if (acpi_ec_poll_mode) - acpi_ec_gpe_poll_query(ec_cxt); - else - acpi_ec_gpe_intr_query(ec_cxt); -} - -static void acpi_ec_gpe_poll_query(void *ec_cxt) -{ - union acpi_ec *ec = (union acpi_ec *)ec_cxt; - u32 value = 0; - static char object_name[5] = { '_', 'Q', '0', '0', '\0' }; - const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - + struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; + u8 value = 0; + static char object_name[8]; - if (!ec_cxt) + if (!ec) goto end; - if (down_interruptible (&ec->poll.sem)) { - return; - } - acpi_hw_low_level_read(8, &value, &ec->common.command_addr); - up(&ec->poll.sem); - - /* TBD: Implement asynch events! - * NOTE: All we care about are EC-SCI's. Other EC events are - * handled via polling (yuck!). This is because some systems - * treat EC-SCIs as level (versus EDGE!) triggered, preventing - * a purely interrupt-driven approach (grumble, grumble). - */ + value = acpi_ec_read_status(ec); + if (!(value & ACPI_EC_FLAG_SCI)) goto end; if (acpi_ec_query(ec, &value)) goto end; - object_name[2] = hex[((value >> 4) & 0x0F)]; - object_name[3] = hex[(value & 0x0F)]; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); + snprintf(object_name, 8, "_Q%2.2X", value); - acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); - end: - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); -} -static void acpi_ec_gpe_intr_query(void *ec_cxt) -{ - union acpi_ec *ec = (union acpi_ec *)ec_cxt; - u32 value; - int result = -ENODATA; - static char object_name[5] = { '_', 'Q', '0', '0', '\0' }; - const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; + acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) - result = acpi_ec_query(ec, &value); - - if (result) - goto end; - - object_name[2] = hex[((value >> 4) & 0x0F)]; - object_name[3] = hex[(value & 0x0F)]; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); - - acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL); end: - atomic_dec(&ec->intr.pending_gpe); - return; + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } static u32 acpi_ec_gpe_handler(void *data) { - if (acpi_ec_poll_mode) - return acpi_ec_gpe_poll_handler(data); - else - return acpi_ec_gpe_intr_handler(data); -} -static u32 acpi_ec_gpe_poll_handler(void *data) -{ acpi_status status = AE_OK; - union acpi_ec *ec = (union acpi_ec *)data; - - if (!ec) - return ACPI_INTERRUPT_NOT_HANDLED; - - acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); - - status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec); - - if (status == AE_OK) - return ACPI_INTERRUPT_HANDLED; - else - return ACPI_INTERRUPT_NOT_HANDLED; -} -static u32 acpi_ec_gpe_intr_handler(void *data) -{ - acpi_status status = AE_OK; - u32 value; - union acpi_ec *ec = (union acpi_ec *)data; - - if (!ec) - return ACPI_INTERRUPT_NOT_HANDLED; + u8 value; + struct acpi_ec *ec = (struct acpi_ec *)data; - acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); + acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR); value = acpi_ec_read_status(ec); - switch (ec->intr.expect_event) { - case ACPI_EC_EVENT_OBF: - if (!(value & ACPI_EC_FLAG_OBF)) - break; - ec->intr.expect_event = 0; - wake_up(&ec->intr.wait); - break; - case ACPI_EC_EVENT_IBE: - if ((value & ACPI_EC_FLAG_IBF)) - break; - ec->intr.expect_event = 0; - wake_up(&ec->intr.wait); - break; - default: - break; + if (acpi_ec_mode == EC_INTR) { + if (acpi_ec_check_status(value, ec->expect_event)) { + ec->expect_event = 0; + wake_up(&ec->wait); + } } if (value & ACPI_EC_FLAG_SCI) { - atomic_add(1, &ec->intr.pending_gpe); - status = acpi_os_execute(OSL_EC_BURST_HANDLER, - acpi_ec_gpe_query, ec); + status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } @@ -833,7 +499,7 @@ acpi_ec_space_handler(u32 function, void *handler_context, void *region_context) { int result = 0; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; u64 temp = *value; acpi_integer f_v = 0; int i = 0; @@ -843,18 +509,16 @@ acpi_ec_space_handler(u32 function, return AE_BAD_PARAMETER; if (bit_width != 8 && acpi_strict) { - printk(KERN_WARNING PREFIX - "acpi_ec_space_handler: bit_width should be 8\n"); return AE_BAD_PARAMETER; } - ec = (union acpi_ec *)handler_context; + ec = (struct acpi_ec *)handler_context; next_byte: switch (function) { case ACPI_READ: temp = 0; - result = acpi_ec_read(ec, (u8) address, (u32 *) & temp); + result = acpi_ec_read(ec, (u8) address, (u8 *) &temp); break; case ACPI_WRITE: result = acpi_ec_write(ec, (u8) address, (u8) temp); @@ -905,20 +569,20 @@ static struct proc_dir_entry *acpi_ec_dir; static int acpi_ec_read_info(struct seq_file *seq, void *offset) { - union acpi_ec *ec = (union acpi_ec *)seq->private; + struct acpi_ec *ec = (struct acpi_ec *)seq->private; if (!ec) goto end; seq_printf(seq, "gpe bit: 0x%02x\n", - (u32) ec->common.gpe_bit); + (u32) ec->gpe_bit); seq_printf(seq, "ports: 0x%02x, 0x%02x\n", - (u32) ec->common.status_addr.address, - (u32) ec->common.data_addr.address); + (u32) ec->command_addr, + (u32) ec->data_addr); seq_printf(seq, "use global lock: %s\n", - ec->common.global_lock ? "yes" : "no"); - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); + ec->global_lock ? "yes" : "no"); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); end: return 0; @@ -929,7 +593,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_ec_read_info, PDE(inode)->data); } -static const struct file_operations acpi_ec_info_ops = { +static struct file_operations acpi_ec_info_ops = { .open = acpi_ec_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -978,101 +642,35 @@ static int acpi_ec_remove_fs(struct acpi_device *device) Driver Interface -------------------------------------------------------------------------- */ -static int acpi_ec_poll_add(struct acpi_device *device) +static int acpi_ec_add(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) return -EINVAL; - ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); + ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec) return -ENOMEM; - memset(ec, 0, sizeof(union acpi_ec)); - - ec->common.handle = device->handle; - ec->common.uid = -1; - init_MUTEX(&ec->poll.sem); - strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_EC_CLASS); - acpi_driver_data(device) = ec; - - /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(ec->common.handle, "_GLK", NULL, - &ec->common.global_lock); - - /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: - http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ - if (ec_ecdt) { - acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, - ACPI_ADR_SPACE_EC, - &acpi_ec_space_handler); - - acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit, - &acpi_ec_gpe_handler); - - kfree(ec_ecdt); + memset(ec, 0, sizeof(struct acpi_ec)); + + ec->handle = device->handle; + ec->uid = -1; + init_MUTEX(&ec->sem); + if (acpi_ec_mode == EC_INTR) { + atomic_set(&ec->leaving_burst, 1); + init_waitqueue_head(&ec->wait); } - - /* Get GPE bit assignment (EC events). */ - /* TODO: Add support for _GPE returning a package */ - status = - acpi_evaluate_integer(ec->common.handle, "_GPE", NULL, - &ec->common.gpe_bit); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit")); - result = -ENODEV; - goto end; - } - - result = acpi_ec_add_fs(device); - if (result) - goto end; - - printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n", - acpi_device_name(device), acpi_device_bid(device), - (u32) ec->common.gpe_bit); - - if (!first_ec) - first_ec = device; - - end: - if (result) - kfree(ec); - - return result; -} -static int acpi_ec_intr_add(struct acpi_device *device) -{ - int result = 0; - acpi_status status = AE_OK; - union acpi_ec *ec = NULL; - - - if (!device) - return -EINVAL; - - ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); - if (!ec) - return -ENOMEM; - memset(ec, 0, sizeof(union acpi_ec)); - - ec->common.handle = device->handle; - ec->common.uid = -1; - atomic_set(&ec->intr.pending_gpe, 0); - atomic_set(&ec->intr.leaving_burst, 1); - init_MUTEX(&ec->intr.sem); - init_waitqueue_head(&ec->intr.wait); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(ec->common.handle, "_GLK", NULL, - &ec->common.global_lock); + acpi_evaluate_integer(ec->handle, "_GLK", NULL, + &ec->global_lock); /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ @@ -1081,7 +679,7 @@ static int acpi_ec_intr_add(struct acpi_device *device) ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); - acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); kfree(ec_ecdt); @@ -1090,10 +688,10 @@ static int acpi_ec_intr_add(struct acpi_device *device) /* Get GPE bit assignment (EC events). */ /* TODO: Add support for _GPE returning a package */ status = - acpi_evaluate_integer(ec->common.handle, "_GPE", NULL, - &ec->common.gpe_bit); + acpi_evaluate_integer(ec->handle, "_GPE", NULL, + &ec->gpe_bit); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n"); + ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment")); result = -ENODEV; goto end; } @@ -1102,14 +700,14 @@ static int acpi_ec_intr_add(struct acpi_device *device) if (result) goto end; - printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", acpi_device_name(device), acpi_device_bid(device), - (u32) ec->common.gpe_bit); + (u32) ec->gpe_bit)); if (!first_ec) first_ec = device; - end: + end: if (result) kfree(ec); @@ -1118,7 +716,7 @@ static int acpi_ec_intr_add(struct acpi_device *device) static int acpi_ec_remove(struct acpi_device *device, int type) { - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) @@ -1136,8 +734,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type) static acpi_status acpi_ec_io_ports(struct acpi_resource *resource, void *context) { - union acpi_ec *ec = (union acpi_ec *)context; - struct acpi_generic_address *addr; + struct acpi_ec *ec = (struct acpi_ec *)context; if (resource->type != ACPI_RESOURCE_TYPE_IO) { return AE_OK; @@ -1148,26 +745,21 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context) * the second address region returned is the status/command * port. */ - if (ec->common.data_addr.register_bit_width == 0) { - addr = &ec->common.data_addr; - } else if (ec->common.command_addr.register_bit_width == 0) { - addr = &ec->common.command_addr; + if (ec->data_addr == 0) { + ec->data_addr = resource->data.io.minimum; + } else if (ec->command_addr == 0) { + ec->command_addr = resource->data.io.minimum; } else { return AE_CTRL_TERMINATE; } - addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO; - addr->register_bit_width = 8; - addr->register_bit_offset = 0; - addr->address = resource->data.io.minimum; - return AE_OK; } static int acpi_ec_start(struct acpi_device *device) { acpi_status status = AE_OK; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) @@ -1181,39 +773,35 @@ static int acpi_ec_start(struct acpi_device *device) /* * Get I/O port addresses. Convert to GAS format. */ - status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS, + status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS, acpi_ec_io_ports, ec); - if (ACPI_FAILURE(status) - || ec->common.command_addr.register_bit_width == 0) { - printk(KERN_ERR PREFIX "Error getting I/O port addresses\n"); + if (ACPI_FAILURE(status) || ec->command_addr == 0) { + ACPI_EXCEPTION((AE_INFO, status, + "Error getting I/O port addresses")); return -ENODEV; } - ec->common.status_addr = ec->common.command_addr; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n", - (u32) ec->common.gpe_bit, - (u32) ec->common.command_addr.address, - (u32) ec->common.data_addr.address)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", + ec->gpe_bit, ec->command_addr, ec->data_addr)); /* * Install GPE handler */ - status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit, + status = acpi_install_gpe_handler(NULL, ec->gpe_bit, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) { return -ENODEV; } - acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); + acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); - status = acpi_install_address_space_handler(ec->common.handle, + status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, &acpi_ec_space_setup, ec); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler); return -ENODEV; } @@ -1224,7 +812,7 @@ static int acpi_ec_start(struct acpi_device *device) static int acpi_ec_stop(struct acpi_device *device, int type) { acpi_status status = AE_OK; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) @@ -1232,14 +820,14 @@ static int acpi_ec_stop(struct acpi_device *device, int type) ec = acpi_driver_data(device); - status = acpi_remove_address_space_handler(ec->common.handle, + status = acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); if (ACPI_FAILURE(status)) return -ENODEV; status = - acpi_remove_gpe_handler(NULL, ec->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler); if (ACPI_FAILURE(status)) return -ENODEV; @@ -1251,76 +839,30 @@ static acpi_status __init acpi_fake_ecdt_callback(acpi_handle handle, u32 Level, void *context, void **retval) { - - if (acpi_ec_poll_mode) - return acpi_fake_ecdt_poll_callback(handle, - Level, context, retval); - else - return acpi_fake_ecdt_intr_callback(handle, - Level, context, retval); -} - -static acpi_status __init -acpi_fake_ecdt_poll_callback(acpi_handle handle, - u32 Level, void *context, void **retval) -{ - acpi_status status; - - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - acpi_ec_io_ports, ec_ecdt); - if (ACPI_FAILURE(status)) - return status; - ec_ecdt->common.status_addr = ec_ecdt->common.command_addr; - - ec_ecdt->common.uid = -1; - acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid); - - status = - acpi_evaluate_integer(handle, "_GPE", NULL, - &ec_ecdt->common.gpe_bit); - if (ACPI_FAILURE(status)) - return status; - init_MUTEX(&ec_ecdt->poll.sem); - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.handle = handle; - - printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n", - (u32) ec_ecdt->common.gpe_bit, - (u32) ec_ecdt->common.command_addr.address, - (u32) ec_ecdt->common.data_addr.address); - - return AE_CTRL_TERMINATE; -} - -static acpi_status __init -acpi_fake_ecdt_intr_callback(acpi_handle handle, - u32 Level, void *context, void **retval) -{ acpi_status status; - init_MUTEX(&ec_ecdt->intr.sem); - init_waitqueue_head(&ec_ecdt->intr.wait); + init_MUTEX(&ec_ecdt->sem); + if (acpi_ec_mode == EC_INTR) { + init_waitqueue_head(&ec_ecdt->wait); + } status = acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_ec_io_ports, ec_ecdt); if (ACPI_FAILURE(status)) return status; - ec_ecdt->common.status_addr = ec_ecdt->common.command_addr; - ec_ecdt->common.uid = -1; - acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid); + ec_ecdt->uid = -1; + acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); status = acpi_evaluate_integer(handle, "_GPE", NULL, - &ec_ecdt->common.gpe_bit); + &ec_ecdt->gpe_bit); if (ACPI_FAILURE(status)) return status; - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.handle = handle; + ec_ecdt->global_lock = TRUE; + ec_ecdt->handle = handle; - printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n", - (u32) ec_ecdt->common.gpe_bit, - (u32) ec_ecdt->common.command_addr.address, - (u32) ec_ecdt->common.data_addr.address); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", + ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr)); return AE_CTRL_TERMINATE; } @@ -1340,14 +882,14 @@ static int __init acpi_ec_fake_ecdt(void) acpi_status status; int ret = 0; - printk(KERN_INFO PREFIX "Try to make an fake ECDT\n"); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT")); - ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); + ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec_ecdt) { ret = -ENOMEM; goto error; } - memset(ec_ecdt, 0, sizeof(union acpi_ec)); + memset(ec_ecdt, 0, sizeof(struct acpi_ec)); status = acpi_get_devices(ACPI_EC_HID, acpi_fake_ecdt_callback, NULL, NULL); @@ -1355,24 +897,16 @@ static int __init acpi_ec_fake_ecdt(void) kfree(ec_ecdt); ec_ecdt = NULL; ret = -ENODEV; + ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT")); goto error; } return 0; - error: - printk(KERN_ERR PREFIX "Can't make an fake ECDT\n"); + error: return ret; } static int __init acpi_ec_get_real_ecdt(void) { - if (acpi_ec_poll_mode) - return acpi_ec_poll_get_real_ecdt(); - else - return acpi_ec_intr_get_real_ecdt(); -} - -static int __init acpi_ec_poll_get_real_ecdt(void) -{ acpi_status status; struct acpi_table_ecdt *ecdt_ptr; @@ -1382,80 +916,36 @@ static int __init acpi_ec_poll_get_real_ecdt(void) if (ACPI_FAILURE(status)) return -ENODEV; - printk(KERN_INFO PREFIX "Found ECDT\n"); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT")); /* * Generate a temporary ec context to use until the namespace is scanned */ - ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); + ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec_ecdt) return -ENOMEM; - memset(ec_ecdt, 0, sizeof(union acpi_ec)); - - ec_ecdt->common.command_addr = ecdt_ptr->ec_control; - ec_ecdt->common.status_addr = ecdt_ptr->ec_control; - ec_ecdt->common.data_addr = ecdt_ptr->ec_data; - ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit; - init_MUTEX(&ec_ecdt->poll.sem); - /* use the GL just to be safe */ - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.uid = ecdt_ptr->uid; + memset(ec_ecdt, 0, sizeof(struct acpi_ec)); - status = - acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle); - if (ACPI_FAILURE(status)) { - goto error; + init_MUTEX(&ec_ecdt->sem); + if (acpi_ec_mode == EC_INTR) { + init_waitqueue_head(&ec_ecdt->wait); } - - return 0; - error: - printk(KERN_ERR PREFIX "Could not use ECDT\n"); - kfree(ec_ecdt); - ec_ecdt = NULL; - - return -ENODEV; -} - -static int __init acpi_ec_intr_get_real_ecdt(void) -{ - acpi_status status; - struct acpi_table_ecdt *ecdt_ptr; - - status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &ecdt_ptr); - if (ACPI_FAILURE(status)) - return -ENODEV; - - printk(KERN_INFO PREFIX "Found ECDT\n"); - - /* - * Generate a temporary ec context to use until the namespace is scanned - */ - ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); - if (!ec_ecdt) - return -ENOMEM; - memset(ec_ecdt, 0, sizeof(union acpi_ec)); - - init_MUTEX(&ec_ecdt->intr.sem); - init_waitqueue_head(&ec_ecdt->intr.wait); - ec_ecdt->common.command_addr = ecdt_ptr->ec_control; - ec_ecdt->common.status_addr = ecdt_ptr->ec_control; - ec_ecdt->common.data_addr = ecdt_ptr->ec_data; - ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit; + ec_ecdt->command_addr = ecdt_ptr->ec_control.address; + ec_ecdt->data_addr = ecdt_ptr->ec_data.address; + ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; /* use the GL just to be safe */ - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.uid = ecdt_ptr->uid; + ec_ecdt->global_lock = TRUE; + ec_ecdt->uid = ecdt_ptr->uid; status = - acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle); + acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); if (ACPI_FAILURE(status)) { goto error; } return 0; - error: - printk(KERN_ERR PREFIX "Could not use ECDT\n"); + error: + ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); kfree(ec_ecdt); ec_ecdt = NULL; @@ -1480,14 +970,14 @@ int __init acpi_ec_ecdt_probe(void) /* * Install GPE handler */ - status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit, + status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec_ecdt); if (ACPI_FAILURE(status)) { goto error; } - acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR); + acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, @@ -1495,7 +985,7 @@ int __init acpi_ec_ecdt_probe(void) &acpi_ec_space_setup, ec_ecdt); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); goto error; } @@ -1503,7 +993,7 @@ int __init acpi_ec_ecdt_probe(void) return 0; error: - printk(KERN_ERR PREFIX "Could not use ECDT\n"); + ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); kfree(ec_ecdt); ec_ecdt = NULL; @@ -1562,13 +1052,13 @@ static int __init acpi_ec_set_intr_mode(char *str) return 0; if (intr) { - acpi_ec_poll_mode = EC_INTR; - acpi_ec_driver.ops.add = acpi_ec_intr_add; + acpi_ec_mode = EC_INTR; } else { - acpi_ec_poll_mode = EC_POLL; - acpi_ec_driver.ops.add = acpi_ec_poll_add; + acpi_ec_mode = EC_POLL; } - printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling"); + acpi_ec_driver.ops.add = acpi_ec_add; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling")); + return 1; } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 6eef4efddcf..ee2a10bf907 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -342,20 +342,8 @@ static u32 acpi_ev_global_lock_handler(void *context) if (acquired) { /* Got the lock, now wake all threads waiting for it */ - acpi_gbl_global_lock_acquired = TRUE; - - /* Run the Global Lock thread which will signal all waiting threads */ - - status = - acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER, - acpi_ev_global_lock_thread, context); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not queue Global Lock thread")); - - return (ACPI_INTERRUPT_NOT_HANDLED); - } + acpi_ev_global_lock_thread(context); } return (ACPI_INTERRUPT_HANDLED); diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 5b3c7a85eb9..203d1359190 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, if (! (ACPI_STRNCMP (object_hID.value, PCI_ROOT_HID_STRING, - sizeof(PCI_ROOT_HID_STRING)) - || - !(ACPI_STRNCMP - (object_hID.value, - PCI_EXPRESS_ROOT_HID_STRING, - sizeof(PCI_EXPRESS_ROOT_HID_STRING))))) - { + sizeof(PCI_ROOT_HID_STRING))) + || + !(ACPI_STRNCMP + (object_hID.value, + PCI_EXPRESS_ROOT_HID_STRING, + sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { /* Install a handler for this PCI root bridge */ diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 15fc12482ba..003a9876c96 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1702,13 +1702,11 @@ static struct ibm_struct ibms[] = { .name = "brightness", .read = brightness_read, .write = brightness_write, - .experimental = 1, }, { .name = "volume", .read = volume_read, .write = volume_write, - .experimental = 1, }, { .name = "fan", diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c index ec6b7f9ede3..2e17ec75af0 100644 --- a/drivers/acpi/motherboard.c +++ b/drivers/acpi/motherboard.c @@ -48,6 +48,12 @@ ACPI_MODULE_NAME("acpi_motherboard") * the io ports if they really know they can use it, while * still preventing hotplug PCI devices from using it. */ + +/* + * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01 + * and PNP0C02, redundant with acpi_reserve_io_ranges(). + * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP. + */ static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data) { struct resource *requested_res = NULL; diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 7f3e7e77e79..d53bd9878ca 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -307,7 +307,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) if (!link || !irq) return -EINVAL; - resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC); + resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); if (!resource) return -ENOMEM; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index fec225d1b6b..fe67a8af520 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -216,10 +216,8 @@ static int acpi_power_off_device(acpi_handle handle) { int result = 0; acpi_status status = AE_OK; - struct acpi_device *device = NULL; struct acpi_power_resource *resource = NULL; - result = acpi_power_get_context(handle, &resource); if (result) return result; @@ -230,13 +228,13 @@ static int acpi_power_off_device(acpi_handle handle) if (resource->references) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is still in use, dereferencing\n", - device->pnp.bus_id)); + resource->device->pnp.bus_id)); return 0; } if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n", - device->pnp.bus_id)); + resource->device->pnp.bus_id)); return 0; } @@ -251,8 +249,7 @@ static int acpi_power_off_device(acpi_handle handle) return -ENOEXEC; /* Update the power resource's _device_ power state */ - device = resource->device; - device->power.state = ACPI_STATE_D3; + resource->device->power.state = ACPI_STATE_D3; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n", resource->name)); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b13d64415b7..1908e0d2022 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -519,7 +519,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr) static void *processor_device_array[NR_CPUS]; -static int acpi_processor_start(struct acpi_device *device) +static int __cpuinit acpi_processor_start(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0a395fca843..65b3f056ad8 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -219,6 +219,23 @@ static void acpi_safe_halt(void) static atomic_t c3_cpu_count; +/* Common C-state entry for C2, C3, .. */ +static void acpi_cstate_enter(struct acpi_processor_cx *cstate) +{ + if (cstate->space_id == ACPI_CSTATE_FFH) { + /* Call into architectural FFH based C-state */ + acpi_processor_ffh_cstate_enter(cstate); + } else { + int unused; + /* IO port based C-state */ + inb(cstate->address); + /* Dummy wait op - must do something useless after P_LVL2 read + because chipsets cannot guarantee that STPCLK# signal + gets asserted in time to freeze execution properly. */ + unused = inl(acpi_fadt.xpm_tmr_blk.address); + } +} + static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -361,11 +378,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); /* Invoke C2 */ - inb(cx->address); - /* Dummy wait op - must do something useless after P_LVL2 read - because chipsets cannot guarantee that STPCLK# signal - gets asserted in time to freeze execution properly. */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); @@ -401,9 +414,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); /* Invoke C3 */ - inb(cx->address); - /* Dummy wait op (see above) */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); if (pr->flags.bm_check) { @@ -628,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) return 0; } -static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr) +static int acpi_processor_get_power_info_default(struct acpi_processor *pr) { - - /* Zero initialize all the C-states info. */ - memset(pr->power.states, 0, sizeof(pr->power.states)); - - /* set the first C-State to C1 */ - pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; - - /* the C0 state only exists as a filler in our array, - * and all processors need to support C1 */ + if (!pr->power.states[ACPI_STATE_C1].valid) { + /* set the first C-State to C1 */ + /* all processors need to support C1 */ + pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; + pr->power.states[ACPI_STATE_C1].valid = 1; + } + /* the C0 state only exists as a filler in our array */ pr->power.states[ACPI_STATE_C0].valid = 1; - pr->power.states[ACPI_STATE_C1].valid = 1; - return 0; } @@ -658,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) if (nocst) return -ENODEV; - current_count = 1; - - /* Zero initialize C2 onwards and prepare for fresh CST lookup */ - for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++) - memset(&(pr->power.states[i]), 0, - sizeof(struct acpi_processor_cx)); + current_count = 0; status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer); if (ACPI_FAILURE(status)) { @@ -718,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) continue; - cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ? - 0 : reg->address; - /* There should be an easy way to extract an integer... */ obj = (union acpi_object *)&(element->package.elements[1]); if (obj->type != ACPI_TYPE_INTEGER) continue; cx.type = obj->integer.value; - - if ((cx.type != ACPI_STATE_C1) && - (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) - continue; - - if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3)) - continue; + /* + * Some buggy BIOSes won't list C1 in _CST - + * Let acpi_processor_get_power_info_default() handle them later + */ + if (i == 1 && cx.type != ACPI_STATE_C1) + current_count++; + + cx.address = reg->address; + cx.index = current_count + 1; + + cx.space_id = ACPI_CSTATE_SYSTEMIO; + if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { + if (acpi_processor_ffh_cstate_probe + (pr->id, &cx, reg) == 0) { + cx.space_id = ACPI_CSTATE_FFH; + } else if (cx.type != ACPI_STATE_C1) { + /* + * C1 is a special case where FIXED_HARDWARE + * can be handled in non-MWAIT way as well. + * In that case, save this _CST entry info. + * That is, we retain space_id of SYSTEM_IO for + * halt based C1. + * Otherwise, ignore this info and continue. + */ + continue; + } + } obj = (union acpi_object *)&(element->package.elements[2]); if (obj->type != ACPI_TYPE_INTEGER) @@ -938,11 +957,17 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) /* NOTE: the idle thread may not be running while calling * this function */ - /* Adding C1 state */ - acpi_processor_get_power_info_default_c1(pr); + /* Zero initialize all the C-states info. */ + memset(pr->power.states, 0, sizeof(pr->power.states)); + result = acpi_processor_get_power_info_cst(pr); if (result == -ENODEV) - acpi_processor_get_power_info_fadt(pr); + result = acpi_processor_get_power_info_fadt(pr); + + if (result) + return result; + + acpi_processor_get_power_info_default(pr); pr->power.count = acpi_processor_power_verify(pr); @@ -1083,6 +1108,7 @@ static const struct file_operations acpi_processor_power_fops = { .release = single_release, }; +#ifdef CONFIG_SMP static void smp_callback(void *v) { /* we already woke the CPU up, nothing more to do */ @@ -1104,8 +1130,9 @@ static int acpi_processor_latency_notify(struct notifier_block *b, static struct notifier_block acpi_processor_latency_notifier = { .notifier_call = acpi_processor_latency_notify, }; +#endif -int acpi_processor_power_init(struct acpi_processor *pr, +int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; @@ -1121,7 +1148,9 @@ int acpi_processor_power_init(struct acpi_processor *pr, "ACPI: processor limited to max C-state %d\n", max_cstate); first_run++; +#ifdef CONFIG_SMP register_latency_notifier(&acpi_processor_latency_notifier); +#endif } if (!pr) @@ -1193,7 +1222,9 @@ int acpi_processor_power_exit(struct acpi_processor *pr, * copies of pm_idle before proceeding. */ cpu_idle_wait(); +#ifdef CONFIG_SMP unregister_latency_notifier(&acpi_processor_latency_notifier); +#endif } return 0; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 62bef0b3b61..8908a975e57 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INFO_MODE; static int update_time = UPDATE_TIME; static int update_time2 = UPDATE_TIME2; -module_param(capacity_mode, int, CAPACITY_UNIT); -module_param(update_mode, int, UPDATE_MODE); -module_param(update_info_mode, int, UPDATE_INFO_MODE); -module_param(update_time, int, UPDATE_TIME); -module_param(update_time2, int, UPDATE_TIME2); +module_param(capacity_mode, int, 0); +module_param(update_mode, int, 0); +module_param(update_info_mode, int, 0); +module_param(update_time, int, 0); +module_param(update_time2, int, 0); static int acpi_sbs_add(struct acpi_device *device); static int acpi_sbs_remove(struct acpi_device *device, int type); @@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_device *device) int acpi_sbs_remove(struct acpi_device *device, int type) { - struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device); + struct acpi_sbs *sbs = NULL; int id; - if (!device || !sbs) { + if (!device) { + return -EINVAL; + } + + sbs = (struct acpi_sbs *)acpi_driver_data(device); + + if (!sbs) { return -EINVAL; } diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 7856db759af..11e2d4454e0 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -324,7 +324,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, if (header->length < sizeof(struct acpi_table_header)) { ACPI_ERROR((AE_INFO, - "Table length (%X) is smaller than minimum (%X)", + "Table length (%X) is smaller than minimum (%zX)", header->length, sizeof(struct acpi_table_header))); return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 0ad3dbb9ebc..86a5fca9b73 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -187,7 +187,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) if (table_ptr->length < sizeof(struct acpi_table_header)) { ACPI_ERROR((AE_INFO, - "RSDT/XSDT length (%X) is smaller than minimum (%X)", + "RSDT/XSDT length (%X) is smaller than minimum (%zX)", table_ptr->length, sizeof(struct acpi_table_header))); diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3f4aa0c99ee..03f6338acc8 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -6,6 +6,7 @@ menu "Serial ATA (prod) and Parallel ATA (experimental) drivers" config ATA tristate "ATA device support" + depends on BLOCK depends on !(M32R || M68K) || BROKEN depends on !SUN4 || BROKEN select SCSI diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 25929123fff..234197e57e9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -334,6 +334,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ /* SiS */ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ @@ -736,8 +744,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) } /* check BUSY/DRQ, perform Command List Override if necessary */ - ahci_tf_read(ap, &tf); - if (tf.command & (ATA_BUSY | ATA_DRQ)) { + if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) { rc = ahci_clo(ap); if (rc == -EOPNOTSUPP) { @@ -1041,7 +1048,7 @@ static void ahci_host_intr(struct ata_port *ap) /* hmmm... a spurious interupt */ /* some devices send D2H reg with I bit set during NCQ command phase */ - if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS) + if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS)) return; /* ignore interim PIO setup fis interrupts */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 5719704eb0e..720174d628f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -126,8 +126,7 @@ enum { ich6_sata = 7, ich6_sata_ahci = 8, ich6m_sata_ahci = 9, - ich7m_sata_ahci = 10, - ich8_sata_ahci = 11, + ich8_sata_ahci = 10, /* constants for mapping table */ P0 = 0, /* port 0 */ @@ -227,7 +226,7 @@ static const struct pci_device_id piix_pci_tbl[] = { /* 82801GB/GR/GH (ICH7, identical to ICH6) */ { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, /* 2801GBM/GHM (ICH7M, identical to ICH6M) */ - { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7m_sata_ahci }, + { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci }, /* Enterprise Southbridge 2 (where's the datasheet?) */ { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, /* SATA Controller 1 IDE (ICH8, no datasheet yet) */ @@ -399,23 +398,10 @@ static const struct piix_map_db ich6m_map_db = { .mask = 0x3, .port_enable = 0x5, .present_shift = 4, - .map = { - /* PM PS SM SS MAP */ - { P0, P2, RV, RV }, /* 00b */ - { RV, RV, RV, RV }, - { P0, P2, IDE, IDE }, /* 10b */ - { RV, RV, RV, RV }, - }, -}; - -static const struct piix_map_db ich7m_map_db = { - .mask = 0x3, - .port_enable = 0x5, - .present_shift = 4, /* Map 01b isn't specified in the doc but some notebooks use - * it anyway. ATM, the only case spotted carries subsystem ID - * 1025:0107. This is the only difference from ich6m. + * it anyway. MAP 01b have been spotted on both ICH6M and + * ICH7M. */ .map = { /* PM PS SM SS MAP */ @@ -432,9 +418,9 @@ static const struct piix_map_db ich8_map_db = { .present_shift = 8, .map = { /* PM PS SM SS MAP */ - { P0, NA, P1, NA }, /* 00b (hardwired) */ + { P0, P2, P1, P3 }, /* 00b (hardwired when in AHCI) */ { RV, RV, RV, RV }, - { RV, RV, RV, RV }, /* 10b (never) */ + { IDE, IDE, NA, NA }, /* 10b (IDE mode) */ { RV, RV, RV, RV }, }, }; @@ -445,7 +431,6 @@ static const struct piix_map_db *piix_map_db_table[] = { [ich6_sata] = &ich6_map_db, [ich6_sata_ahci] = &ich6_map_db, [ich6m_sata_ahci] = &ich6m_map_db, - [ich7m_sata_ahci] = &ich7m_map_db, [ich8_sata_ahci] = &ich8_map_db, }; @@ -556,19 +541,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich7m_sata_ahci: 10 */ - { - .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 */ - .port_ops = &piix_sata_ops, - }, - - /* ich8_sata_ahci: 11 */ + /* ich8_sata_ahci: 10 */ { .sht = &piix_sht, .flags = ATA_FLAG_SATA | diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 77138a39eb0..915a55a6cc1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -870,7 +870,11 @@ static unsigned int ata_id_xfermask(const u16 *id) * the PIO timing number for the maximum. Turn it into * a mask. */ - pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ; + u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF; + if (mode < 5) /* Valid PIO range */ + pio_mask = (2 << mode) - 1; + else + pio_mask = 1; /* But wait.. there's more. Design your standards by * committee and you too can get a free iordy field to @@ -5953,7 +5957,7 @@ static void __exit ata_exit(void) destroy_workqueue(ata_aux_wq); } -module_init(ata_init); +subsys_initcall(ata_init); module_exit(ata_exit); static unsigned long ratelimit_time; @@ -6118,7 +6122,6 @@ EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); -EXPORT_SYMBOL_GPL(ata_dev_revalidate); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_port_disable); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b0d0cc41f3e..5c1fc467fc7 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -164,10 +164,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) { int rc = 0; u8 scsi_cmd[MAX_COMMAND_SIZE]; - u8 args[4], *argbuf = NULL; + u8 args[4], *argbuf = NULL, *sensebuf = NULL; int argsize = 0; - struct scsi_sense_hdr sshdr; enum dma_data_direction data_dir; + int cmd_result; if (arg == NULL) return -EINVAL; @@ -175,6 +175,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) if (copy_from_user(args, arg, sizeof(args))) return -EFAULT; + sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); + if (!sensebuf) + return -ENOMEM; + memset(scsi_cmd, 0, sizeof(scsi_cmd)); if (args[3]) { @@ -191,7 +195,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) data_dir = DMA_FROM_DEVICE; } else { scsi_cmd[1] = (3 << 1); /* Non-data */ - /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + scsi_cmd[2] = 0x20; /* cc but no off.line or data xfer */ data_dir = DMA_NONE; } @@ -210,18 +214,46 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) /* Good values for timeout and retries? Values below from scsi_ioctl_send_command() for default case... */ - if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize, - &sshdr, (10*HZ), 5)) { + cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize, + sensebuf, (10*HZ), 5, 0); + + if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */ + u8 *desc = sensebuf + 8; + cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ + + /* If we set cc then ATA pass-through will cause a + * check condition even if no error. Filter that. */ + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, + &sshdr); + if (sshdr.sense_key==0 && + sshdr.asc==0 && sshdr.ascq==0) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + + /* Send userspace a few ATA registers (same as drivers/ide) */ + if (sensebuf[0] == 0x72 && /* format is "descriptor" */ + desc[0] == 0x09 ) { /* code is "ATA Descriptor" */ + args[0] = desc[13]; /* status */ + args[1] = desc[3]; /* error */ + args[2] = desc[5]; /* sector count (0:7) */ + if (copy_to_user(arg, args, sizeof(args))) + rc = -EFAULT; + } + } + + + if (cmd_result) { rc = -EIO; goto error; } - /* Need code to retrieve data from check condition? */ - if ((argbuf) && copy_to_user(arg + sizeof(args), argbuf, argsize)) rc = -EFAULT; error: + kfree(sensebuf); kfree(argbuf); return rc; } @@ -1580,9 +1612,9 @@ early_finish: err_did: ata_qc_free(qc); -err_mem: cmd->result = (DID_ERROR << 16); done(cmd); +err_mem: DPRINTK("EXIT - internal\n"); return 0; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 06daaa3736a..7645f2b30cc 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -981,6 +981,15 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, mask = (1 << 2) | (1 << 0); if ((tmp8 & mask) != mask) legacy_mode = (1 << 3); +#if defined(CONFIG_NO_ATA_LEGACY) + /* Some platforms with PCI limits cannot address compat + port space. In that case we punt if their firmware has + left a device in compatibility mode */ + if (legacy_mode) { + printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); + return -EOPNOTSUPP; + } +#endif } rc = pci_request_regions(pdev, DRV_NAME); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a5ecb71390a..0ed263be652 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -53,6 +53,7 @@ extern unsigned ata_exec_internal(struct ata_device *dev, extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int post_reset, u16 *id); +extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern int ata_dev_configure(struct ata_device *dev, int print_info); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 29234c89711..5c47a9e0e0c 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -677,6 +677,8 @@ static const struct pci_device_id amd[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 8 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 8 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 8 }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 }, { }, diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 690828eb522..96a098020a8 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -92,7 +92,7 @@ static int artop6260_pre_reset(struct ata_port *ap) return -ENOENT; pci_read_config_byte(pdev, 0x49, &tmp); - if (tmp & (1 >> ap->port_no)) + if (tmp & (1 << ap->port_no)) ap->cbl = ATA_CBL_PATA40; else ap->cbl = ATA_CBL_PATA80; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 7350443948c..fce3fcdc7e7 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.5" +#define DRV_VERSION "0.5.1" struct hpt_clock { u8 xfer_speed; @@ -453,7 +453,13 @@ static int hpt37x_pre_reset(struct ata_port *ap) { u8 scr2, ata66; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - + static const struct pci_bits hpt37x_enable_bits[] = { + { 0x50, 1, 0x04, 0x04 }, + { 0x54, 1, 0x04, 0x04 } + }; + if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) + return -ENOENT; + pci_read_config_byte(pdev, 0x5B, &scr2); pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01); /* Cable register now active */ @@ -488,10 +494,17 @@ static void hpt37x_error_handler(struct ata_port *ap) static int hpt374_pre_reset(struct ata_port *ap) { + static const struct pci_bits hpt37x_enable_bits[] = { + { 0x50, 1, 0x04, 0x04 }, + { 0x54, 1, 0x04, 0x04 } + }; u16 mcr3, mcr6; u8 ata66; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) + return -ENOENT; + /* Do the extra channel work */ pci_read_config_word(pdev, 0x52, &mcr3); pci_read_config_word(pdev, 0x56, &mcr6); diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 7977f471d5e..2c3cc0ccc60 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -141,7 +141,7 @@ static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned memcpy(&pad, buf + buflen - slop, slop); outl(le32_to_cpu(pad), ap->ioaddr.data_addr); } else { - pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + pad = cpu_to_le32(inl(ap->ioaddr.data_addr)); memcpy(buf + buflen - slop, &pad, slop); } } diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 323b6071080..d65ebfd7c7b 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -117,10 +117,14 @@ static const struct pci_device_id nv_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, - { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC }, - { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC }, - { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC }, - { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC }, + { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x0550), GENERIC }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0551), GENERIC }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0552), GENERIC }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0553), GENERIC }, /* MCP67 */ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 8bcdfa64667..72eda5160fa 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -260,6 +260,7 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = { #if 0 { PCI_VDEVICE(PROMISE, 0x3570), board_20771 }, #endif + { PCI_VDEVICE(PROMISE, 0x3577), board_20771 }, { } /* terminate list */ }; diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 0738f52463a..9d1235ba06b 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -240,7 +240,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_probe_ent *probe_ent = NULL; int rc; u32 genctl; - struct ata_port_info *ppi[2]; + struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi }; int pci_dev_busy = 0; u8 pmr; u8 port2_start; @@ -265,27 +265,20 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_regions; - ppi[0] = ppi[1] = &sis_port_info; - probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); - if (!probe_ent) { - rc = -ENOMEM; - goto err_out_regions; - } - /* check and see if the SCRs are in IO space or PCI cfg space */ pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) - probe_ent->port_flags |= SIS_FLAG_CFGSCR; + pi.flags |= SIS_FLAG_CFGSCR; /* if hardware thinks SCRs are in IO space, but there are * no IO resources assigned, change to PCI cfg space. */ - if ((!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) && + if ((!(pi.flags & SIS_FLAG_CFGSCR)) && ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) || (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) { genctl &= ~GENCTL_IOMAPPED_SCR; pci_write_config_dword(pdev, SIS_GENCTL, genctl); - probe_ent->port_flags |= SIS_FLAG_CFGSCR; + pi.flags |= SIS_FLAG_CFGSCR; } pci_read_config_byte(pdev, SIS_PMR, &pmr); @@ -306,6 +299,12 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) port2_start = 0x20; } + probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + if (!probe_ent) { + rc = -ENOMEM; + goto err_out_regions; + } + if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) { probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR); diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index f4455a1efe2..1c7f19aecc2 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -230,7 +230,7 @@ static int vt6420_prereset(struct ata_port *ap) int online; /* don't do any SCR stuff if we're not loading */ - if (!ATA_PFLAG_LOADING) + if (!(ap->pflags & ATA_PFLAG_LOADING)) goto skip_scr; /* Resume phy. This is the old resume sequence from diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 323592de047..9fffa7af6db 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -2452,8 +2452,8 @@ static int __init amb_module_init (void) static void __exit amb_module_exit (void) { PRINTD (DBG_FLOW|DBG_INIT, "cleanup_module"); - - return pci_unregister_driver(&amb_driver); + + pci_unregister_driver(&amb_driver); } module_init(amb_module_init); diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 40ab9b65fae..697ad82f663 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1002,6 +1002,10 @@ static int fs_open(struct atm_vcc *atm_vcc) r = ROUND_UP; } error = make_rate (pcr, r, &tmc0, NULL); + if (error) { + kfree(tc); + return error; + } } fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr); } diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index f59349206dd..4dc10105d61 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -1789,7 +1789,7 @@ static inline void CLOCK_IT (const hrz_dev *dev, u32 ctrl) WRITE_IT_WAIT(dev, ctrl | SEEPROM_SK); } -static u16 __init read_bia (const hrz_dev * dev, u16 addr) +static u16 __devinit read_bia (const hrz_dev * dev, u16 addr) { u32 ctrl = rd_regl (dev, CONTROL_0_REG); @@ -2932,8 +2932,8 @@ static int __init hrz_module_init (void) { static void __exit hrz_module_exit (void) { PRINTD (DBG_FLOW, "cleanup_module"); - - return pci_unregister_driver(&hrz_driver); + + pci_unregister_driver(&hrz_driver); } module_init(hrz_module_init); diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 632ede55276..bd090459480 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -2759,7 +2759,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) { ns_dev *card; pool_levels pl; - int btype; + long btype; unsigned long flags; card = dev->dev_data; @@ -2859,7 +2859,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) case NS_ADJBUFLEV: if (!capable(CAP_NET_ADMIN)) return -EPERM; - btype = (int) arg; /* an int is the same size as a pointer */ + btype = (long) arg; /* a long is the same size as a pointer or bigger */ switch (btype) { case NS_BUFTYPE_SMALL: diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 0b4e2243693..1429f3a2629 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -37,8 +37,8 @@ config DEBUG_DRIVER If you are unsure about this, say N here. -endmenu - config SYS_HYPERVISOR bool default n + +endmenu diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 12173d16bea..7d8a7ce73fb 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -372,19 +372,30 @@ int bus_add_device(struct device * dev) pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); error = device_add_attrs(bus, dev); if (error) - goto out; + goto out_put; error = sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); if (error) - goto out; + goto out_id; error = sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem"); if (error) - goto out; + goto out_subsys; error = sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); + if (error) + goto out_deprecated; } -out: + return 0; + +out_deprecated: + sysfs_remove_link(&dev->kobj, "subsystem"); +out_subsys: + sysfs_remove_link(&bus->devices.kobj, dev->bus_id); +out_id: + device_remove_attrs(bus, dev); +out_put: + put_bus(dev->bus); return error; } @@ -428,8 +439,10 @@ void bus_remove_device(struct device * dev) sysfs_remove_link(&dev->kobj, "bus"); sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); - dev->is_registered = 0; - klist_del(&dev->knode_bus); + if (dev->is_registered) { + dev->is_registered = 0; + klist_del(&dev->knode_bus); + } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); put_bus(dev->bus); @@ -505,34 +518,36 @@ int bus_add_driver(struct device_driver *drv) struct bus_type * bus = get_bus(drv->bus); int error = 0; - if (bus) { - pr_debug("bus %s: add driver %s\n", bus->name, drv->name); - error = kobject_set_name(&drv->kobj, "%s", drv->name); - if (error) - goto out_put_bus; - drv->kobj.kset = &bus->drivers; - if ((error = kobject_register(&drv->kobj))) - goto out_put_bus; - - error = driver_attach(drv); - if (error) - goto out_unregister; - klist_add_tail(&drv->knode_bus, &bus->klist_drivers); - module_add_driver(drv->owner, drv); - - error = driver_add_attrs(bus, drv); - if (error) { - /* How the hell do we get out of this pickle? Give up */ - printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", - __FUNCTION__, drv->name); - } - error = add_bind_files(drv); - if (error) { - /* Ditto */ - printk(KERN_ERR "%s: add_bind_files(%s) failed\n", - __FUNCTION__, drv->name); - } + if (!bus) + return 0; + + pr_debug("bus %s: add driver %s\n", bus->name, drv->name); + error = kobject_set_name(&drv->kobj, "%s", drv->name); + if (error) + goto out_put_bus; + drv->kobj.kset = &bus->drivers; + if ((error = kobject_register(&drv->kobj))) + goto out_put_bus; + + error = driver_attach(drv); + if (error) + goto out_unregister; + klist_add_tail(&drv->knode_bus, &bus->klist_drivers); + module_add_driver(drv->owner, drv); + + error = driver_add_attrs(bus, drv); + if (error) { + /* How the hell do we get out of this pickle? Give up */ + printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", + __FUNCTION__, drv->name); } + error = add_bind_files(drv); + if (error) { + /* Ditto */ + printk(KERN_ERR "%s: add_bind_files(%s) failed\n", + __FUNCTION__, drv->name); + } + return error; out_unregister: kobject_unregister(&drv->kobj); @@ -552,16 +567,17 @@ out_put_bus: void bus_remove_driver(struct device_driver * drv) { - if (drv->bus) { - remove_bind_files(drv); - driver_remove_attrs(drv->bus, drv); - klist_remove(&drv->knode_bus); - pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); - driver_detach(drv); - module_remove_driver(drv); - kobject_unregister(&drv->kobj); - put_bus(drv->bus); - } + if (!drv->bus) + return; + + remove_bind_files(drv); + driver_remove_attrs(drv->bus, drv); + klist_remove(&drv->knode_bus); + pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); + driver_detach(drv); + module_remove_driver(drv); + kobject_unregister(&drv->kobj); + put_bus(drv->bus); } @@ -732,11 +748,15 @@ int bus_register(struct bus_type * bus) klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_drivers, NULL, NULL); - bus_add_attrs(bus); + retval = bus_add_attrs(bus); + if (retval) + goto bus_attrs_fail; pr_debug("bus type '%s' registered\n", bus->name); return 0; +bus_attrs_fail: + kset_unregister(&bus->drivers); bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: diff --git a/drivers/base/class.c b/drivers/base/class.c index b32b77ff2dc..0ff267a248d 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -562,7 +562,10 @@ int class_device_add(struct class_device *class_dev) goto out2; /* add the needed attributes to this device */ - sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem"); + error = sysfs_create_link(&class_dev->kobj, + &parent_class->subsys.kset.kobj, "subsystem"); + if (error) + goto out3; class_dev->uevent_attr.attr.name = "uevent"; class_dev->uevent_attr.attr.mode = S_IWUSR; class_dev->uevent_attr.attr.owner = parent_class->owner; diff --git a/drivers/base/core.c b/drivers/base/core.c index b224bb43ff6..68ad11af22b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -44,7 +44,7 @@ const char *dev_driver_string(struct device *dev) return dev->driver ? dev->driver->name : (dev->bus ? dev->bus->name : ""); } -EXPORT_SYMBOL_GPL(dev_driver_string); +EXPORT_SYMBOL(dev_driver_string); #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) @@ -433,14 +433,16 @@ int device_add(struct device *dev) if (dev->driver) dev->uevent_attr.attr.owner = dev->driver->owner; dev->uevent_attr.store = store_uevent; - device_create_file(dev, &dev->uevent_attr); + error = device_create_file(dev, &dev->uevent_attr); + if (error) + goto attrError; if (MAJOR(dev->devt)) { struct device_attribute *attr; attr = kzalloc(sizeof(*attr), GFP_KERNEL); if (!attr) { error = -ENOMEM; - goto PMError; + goto ueventattrError; } attr->attr.name = "dev"; attr->attr.mode = S_IRUGO; @@ -450,7 +452,7 @@ int device_add(struct device *dev) error = device_create_file(dev, attr); if (error) { kfree(attr); - goto attrError; + goto ueventattrError; } dev->devt_attr = attr; @@ -477,7 +479,8 @@ int device_add(struct device *dev) if ((error = bus_add_device(dev))) goto BusError; kobject_uevent(&dev->kobj, KOBJ_ADD); - bus_attach_device(dev); + if ((error = bus_attach_device(dev))) + goto AttachError; if (parent) klist_add_tail(&dev->knode_parent, &parent->klist_children); @@ -496,6 +499,8 @@ int device_add(struct device *dev) kfree(class_name); put_device(dev); return error; + AttachError: + bus_remove_device(dev); BusError: device_pm_remove(dev); PMError: @@ -507,6 +512,8 @@ int device_add(struct device *dev) device_remove_file(dev, dev->devt_attr); kfree(dev->devt_attr); } + ueventattrError: + device_remove_file(dev, &dev->uevent_attr); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); @@ -805,8 +812,10 @@ int device_rename(struct device *dev, char *new_name) if (dev->class) { old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); - if (!old_symlink_name) - return -ENOMEM; + if (!old_symlink_name) { + error = -ENOMEM; + goto out_free_old_class; + } strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); } @@ -830,9 +839,10 @@ int device_rename(struct device *dev, char *new_name) } put_device(dev); - kfree(old_class_name); kfree(new_class_name); kfree(old_symlink_name); + out_free_old_class: + kfree(old_class_name); return error; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b5f43c3e44f..c5d6bb4290a 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -18,6 +18,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/kthread.h> +#include <linux/wait.h> #include "base.h" #include "power/power.h" @@ -70,6 +71,8 @@ struct stupid_thread_structure { }; static atomic_t probe_count = ATOMIC_INIT(0); +static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); + static int really_probe(void *void_data) { struct stupid_thread_structure *data = void_data; @@ -121,6 +124,7 @@ probe_failed: done: kfree(data); atomic_dec(&probe_count); + wake_up(&probe_waitqueue); return ret; } @@ -171,6 +175,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) drv->bus->name, dev->bus_id, drv->name); data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; data->drv = drv; data->dev = dev; @@ -178,7 +184,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) probe_task = kthread_run(really_probe, data, "probe-%s", dev->bus_id); if (IS_ERR(probe_task)) - ret = PTR_ERR(probe_task); + ret = really_probe(data); } else ret = really_probe(data); @@ -335,6 +341,32 @@ void driver_detach(struct device_driver * drv) } } +#ifdef CONFIG_PCI_MULTITHREAD_PROBE +static int __init wait_for_probes(void) +{ + DEFINE_WAIT(wait); + + printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__, + atomic_read(&probe_count)); + if (!atomic_read(&probe_count)) + return 0; + while (atomic_read(&probe_count)) { + prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE); + if (atomic_read(&probe_count)) + schedule(); + } + finish_wait(&probe_waitqueue, &wait); + return 0; +} + +core_initcall_sync(wait_for_probes); +postcore_initcall_sync(wait_for_probes); +arch_initcall_sync(wait_for_probes); +subsys_initcall_sync(wait_for_probes); +fs_initcall_sync(wait_for_probes); +device_initcall_sync(wait_for_probes); +late_initcall_sync(wait_for_probes); +#endif EXPORT_SYMBOL_GPL(device_bind_driver); EXPORT_SYMBOL_GPL(device_release_driver); diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index 33c5cce1560..b2efbd4cf71 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -141,11 +141,20 @@ dma_pool_create (const char *name, struct device *dev, init_waitqueue_head (&retval->waitq); if (dev) { + int ret; + down (&pools_lock); if (list_empty (&dev->dma_pools)) - device_create_file (dev, &dev_attr_pools); + ret = device_create_file (dev, &dev_attr_pools); + else + ret = 0; /* note: not currently insisting "name" be unique */ - list_add (&retval->pools, &dev->dma_pools); + if (!ret) + list_add (&retval->pools, &dev->dma_pools); + else { + kfree(retval); + retval = NULL; + } up (&pools_lock); } else INIT_LIST_HEAD (&retval->pools); diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 3ef9d514b91..28dccb730af 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -97,8 +97,7 @@ static struct attribute_group topology_attr_group = { /* Add/Remove cpu_topology interface for CPU device */ static int __cpuinit topology_add_dev(struct sys_device * sys_dev) { - sysfs_create_group(&sys_dev->kobj, &topology_attr_group); - return 0; + return sysfs_create_group(&sys_dev->kobj, &topology_attr_group); } static int __cpuinit topology_remove_dev(struct sys_device * sys_dev) diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index cec539e601f..6148073532b 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -4379,8 +4379,8 @@ static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry) static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState) { memcpy(DeviceState + 2, DeviceState + 3, 1); - memcpy(DeviceState + 4, DeviceState + 5, 2); - memcpy(DeviceState + 6, DeviceState + 8, 4); + memmove(DeviceState + 4, DeviceState + 5, 2); + memmove(DeviceState + 6, DeviceState + 8, 4); } static inline diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 5d254b71450..5d656217153 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1709,10 +1709,13 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) return get_disk(unit[drive].gendisk); } -int __init amiga_floppy_init(void) +static int __init amiga_floppy_init(void) { int i, ret; + if (!MACH_IS_AMIGA) + return -ENXIO; + if (!AMIGAHW_PRESENT(AMI_FLOPPY)) return -ENXIO; @@ -1809,15 +1812,9 @@ out_blkdev: return ret; } +module_init(amiga_floppy_init); #ifdef MODULE -int init_module(void) -{ - if (!MACH_IS_AMIGA) - return -ENXIO; - return amiga_floppy_init(); -} - #if 0 /* not safe to unload */ void cleanup_module(void) { diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 6eebcb7be97..6d111228cfa 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "22" +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +#define VERSION "32" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" @@ -65,7 +65,7 @@ struct aoe_atahdr { struct aoe_cfghdr { __be16 bufcnt; __be16 fwver; - unsigned char res; + unsigned char scnt; unsigned char aoeccmd; unsigned char cslen[2]; }; @@ -78,12 +78,14 @@ enum { DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */ DEVFL_PAUSE = (1<<5), DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */ + DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */ + DEVFL_KICKME = (1<<8), BUFFL_FAIL = 1, }; enum { - MAXATADATA = 1024, + DEFAULTBCNT = 2 * 512, /* 2 sectors */ NPERSHELF = 16, /* number of slots per shelf address */ FREETAG = -1, MIN_BUFS = 8, @@ -107,11 +109,9 @@ struct frame { ulong waited; struct buf *buf; char *bufaddr; - int writedatalen; - int ndata; - - /* largest possible */ - unsigned char data[sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr)]; + ulong bcnt; + sector_t lba; + struct sk_buff *skb; }; struct aoedev { @@ -121,9 +121,12 @@ struct aoedev { ulong sysminor; ulong aoemajor; ulong aoeminor; - ulong nopen; /* (bd_openers isn't available without sleeping) */ - ulong rttavg; /* round trip average of requests/responses */ + u16 nopen; /* (bd_openers isn't available without sleeping) */ + u16 lasttag; /* last tag sent */ + u16 rttavg; /* round trip average of requests/responses */ + u16 mintimer; u16 fw_ver; /* version of blade's firmware */ + u16 maxbcnt; struct work_struct work;/* disk create work struct */ struct gendisk *gd; request_queue_t blkq; @@ -137,8 +140,8 @@ struct aoedev { mempool_t *bufpool; /* for deadlock-free Buf allocation */ struct list_head bufq; /* queue of bios to work on */ struct buf *inprocess; /* the one we're currently working on */ - ulong lasttag; /* last tag sent */ - ulong nframes; /* number of frames below */ + ushort lostjumbo; + ushort nframes; /* number of frames below */ struct frame *frames; }; @@ -157,6 +160,7 @@ void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor); void aoecmd_ata_rsp(struct sk_buff *); void aoecmd_cfg_rsp(struct sk_buff *); void aoecmd_sleepwork(void *vp); +struct sk_buff *new_skb(ulong); int aoedev_init(void); void aoedev_exit(void); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 393b86a3dbf..aa25f8b09fe 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoeblk.c * block device routines @@ -14,7 +14,6 @@ static kmem_cache_t *buf_pool_cache; -/* add attributes for our block devices in sysfs */ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) { struct aoedev *d = disk->private_data; @@ -64,21 +63,27 @@ static struct disk_attribute disk_attr_fwver = { .show = aoedisk_show_fwver }; -static void +static struct attribute *aoe_attrs[] = { + &disk_attr_state.attr, + &disk_attr_mac.attr, + &disk_attr_netif.attr, + &disk_attr_fwver.attr, + NULL +}; + +static const struct attribute_group attr_group = { + .attrs = aoe_attrs, +}; + +static int aoedisk_add_sysfs(struct aoedev *d) { - sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr); - sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr); - sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr); - sysfs_create_file(&d->gd->kobj, &disk_attr_fwver.attr); + return sysfs_create_group(&d->gd->kobj, &attr_group); } void aoedisk_rm_sysfs(struct aoedev *d) { - sysfs_remove_link(&d->gd->kobj, "state"); - sysfs_remove_link(&d->gd->kobj, "mac"); - sysfs_remove_link(&d->gd->kobj, "netif"); - sysfs_remove_link(&d->gd->kobj, "firmware-version"); + sysfs_remove_group(&d->gd->kobj, &attr_group); } static int @@ -132,8 +137,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) d = bio->bi_bdev->bd_disk->private_data; buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { - printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation " - "failure\n"); + printk(KERN_INFO "aoe: buf allocation failure\n"); bio_endio(bio, bio->bi_size, -ENOMEM); return 0; } @@ -143,14 +147,15 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) buf->bio = bio; buf->resid = bio->bi_size; buf->sector = bio->bi_sector; - buf->bv = buf->bio->bi_io_vec; + buf->bv = &bio->bi_io_vec[bio->bi_idx]; + WARN_ON(buf->bv->bv_len == 0); buf->bv_resid = buf->bv->bv_len; buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; spin_lock_irqsave(&d->lock, flags); if ((d->flags & DEVFL_UP) == 0) { - printk(KERN_INFO "aoe: aoeblk_make_request: device %ld.%ld is not up\n", + printk(KERN_INFO "aoe: device %ld.%ld is not up\n", d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); @@ -176,7 +181,7 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo) struct aoedev *d = bdev->bd_disk->private_data; if ((d->flags & DEVFL_UP) == 0) { - printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n"); + printk(KERN_ERR "aoe: disk not up\n"); return -ENODEV; } @@ -203,8 +208,8 @@ aoeblk_gdalloc(void *vp) gd = alloc_disk(AOE_PARTITIONS); if (gd == NULL) { - printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk " - "structure for %ld.%ld\n", d->aoemajor, d->aoeminor); + printk(KERN_ERR "aoe: cannot allocate disk structure for %ld.%ld\n", + d->aoemajor, d->aoeminor); spin_lock_irqsave(&d->lock, flags); d->flags &= ~DEVFL_GDALLOC; spin_unlock_irqrestore(&d->lock, flags); @@ -213,8 +218,8 @@ aoeblk_gdalloc(void *vp) d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache); if (d->bufpool == NULL) { - printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool " - "for %ld.%ld\n", d->aoemajor, d->aoeminor); + printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%ld\n", + d->aoemajor, d->aoeminor); put_disk(gd); spin_lock_irqsave(&d->lock, flags); d->flags &= ~DEVFL_GDALLOC; diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 1bc1cf9603f..e22b4c9520a 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoechr.c * AoE character device driver @@ -15,7 +15,6 @@ enum { MINOR_INTERFACES, MINOR_REVALIDATE, MSGSZ = 2048, - NARGS = 10, NMSG = 100, /* message backlog to retain */ }; @@ -56,9 +55,8 @@ static int interfaces(const char __user *str, size_t size) { if (set_aoe_iflist(str, size)) { - printk(KERN_CRIT - "%s: could not set interface list: %s\n", - __FUNCTION__, "too many interfaces"); + printk(KERN_ERR + "aoe: could not set interface list: too many interfaces\n"); return -EINVAL; } return 0; @@ -81,8 +79,7 @@ revalidate(const char __user *str, size_t size) /* should be e%d.%d format */ n = sscanf(buf, "e%d.%d", &major, &minor); if (n != 2) { - printk(KERN_ERR "aoe: %s: invalid device specification\n", - __FUNCTION__); + printk(KERN_ERR "aoe: invalid device specification\n"); return -EINVAL; } d = aoedev_by_aoeaddr(major, minor); @@ -90,6 +87,7 @@ revalidate(const char __user *str, size_t size) return -EINVAL; spin_lock_irqsave(&d->lock, flags); + d->flags &= ~DEVFL_MAXBCNT; d->flags |= DEVFL_PAUSE; spin_unlock_irqrestore(&d->lock, flags); aoecmd_cfg(major, minor); @@ -116,7 +114,7 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags); mp = kmalloc(n, GFP_ATOMIC); if (mp == NULL) { - printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ld\n", n); + printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n); goto bail; } @@ -141,7 +139,7 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp switch ((unsigned long) filp->private_data) { default: - printk(KERN_INFO "aoe: aoechr_write: can't write to that file.\n"); + printk(KERN_INFO "aoe: can't write to that file.\n"); break; case MINOR_DISCOVER: ret = discover(); @@ -250,7 +248,7 @@ aoechr_init(void) n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops); if (n < 0) { - printk(KERN_ERR "aoe: aoechr_init: can't register char device\n"); + printk(KERN_ERR "aoe: can't register char device\n"); return n; } sema_init(&emsgs_sema, 0); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 39da28d344f..8a13b1af8ba 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoecmd.c * Filesystem request handling methods @@ -15,17 +15,19 @@ #define TIMERTICK (HZ / 10) #define MINTIMER (2 * TIMERTICK) #define MAXTIMER (HZ << 1) -#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */ -static struct sk_buff * -new_skb(struct net_device *if_dev, ulong len) +static int aoe_deadsecs = 60 * 3; +module_param(aoe_deadsecs, int, 0644); +MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); + +struct sk_buff * +new_skb(ulong len) { struct sk_buff *skb; skb = alloc_skb(len, GFP_ATOMIC); if (skb) { skb->nh.raw = skb->mac.raw = skb->data; - skb->dev = if_dev; skb->protocol = __constant_htons(ETH_P_AOE); skb->priority = 0; skb_put(skb, len); @@ -40,29 +42,6 @@ new_skb(struct net_device *if_dev, ulong len) return skb; } -static struct sk_buff * -skb_prepare(struct aoedev *d, struct frame *f) -{ - struct sk_buff *skb; - char *p; - - skb = new_skb(d->ifp, f->ndata + f->writedatalen); - if (!skb) { - printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n"); - return NULL; - } - - p = skb->mac.raw; - memcpy(p, f->data, f->ndata); - - if (f->writedatalen) { - p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); - memcpy(p, f->bufaddr, f->writedatalen); - } - - return skb; -} - static struct frame * getframe(struct aoedev *d, int tag) { @@ -107,6 +86,17 @@ aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h) return host_tag; } +static inline void +put_lba(struct aoe_atahdr *ah, sector_t lba) +{ + ah->lba0 = lba; + ah->lba1 = lba >>= 8; + ah->lba2 = lba >>= 8; + ah->lba3 = lba >>= 8; + ah->lba4 = lba >>= 8; + ah->lba5 = lba >>= 8; +} + static void aoecmd_ata_rw(struct aoedev *d, struct frame *f) { @@ -125,29 +115,27 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) sector = buf->sector; bcnt = buf->bv_resid; - if (bcnt > MAXATADATA) - bcnt = MAXATADATA; + if (bcnt > d->maxbcnt) + bcnt = d->maxbcnt; /* initialize the headers & frame */ - h = (struct aoe_hdr *) f->data; + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - f->ndata = sizeof *h + sizeof *ah; - memset(h, 0, f->ndata); + skb->len = sizeof *h + sizeof *ah; + memset(h, 0, ETH_ZLEN); f->tag = aoehdr_atainit(d, h); f->waited = 0; f->buf = buf; f->bufaddr = buf->bufaddr; + f->bcnt = bcnt; + f->lba = sector; /* set up ata header */ ah->scnt = bcnt >> 9; - ah->lba0 = sector; - ah->lba1 = sector >>= 8; - ah->lba2 = sector >>= 8; - ah->lba3 = sector >>= 8; + put_lba(ah, sector); if (d->flags & DEVFL_EXT) { ah->aflags |= AOEAFL_EXT; - ah->lba4 = sector >>= 8; - ah->lba5 = sector >>= 8; } else { extbit = 0; ah->lba3 &= 0x0f; @@ -155,11 +143,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) } if (bio_data_dir(buf->bio) == WRITE) { + skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), + offset_in_page(f->bufaddr), bcnt); ah->aflags |= AOEAFL_WRITE; - f->writedatalen = bcnt; + skb->len += bcnt; + skb->data_len = bcnt; } else { + skb->len = ETH_ZLEN; writebit = 0; - f->writedatalen = 0; } ah->cmdstat = WIN_READ | writebit | extbit; @@ -168,26 +159,27 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) buf->nframesout += 1; buf->bufaddr += bcnt; buf->bv_resid -= bcnt; -/* printk(KERN_INFO "aoe: bv_resid=%ld\n", buf->bv_resid); */ +/* printk(KERN_DEBUG "aoe: bv_resid=%ld\n", buf->bv_resid); */ buf->resid -= bcnt; buf->sector += bcnt >> 9; if (buf->resid == 0) { d->inprocess = NULL; } else if (buf->bv_resid == 0) { buf->bv++; + WARN_ON(buf->bv->bv_len == 0); buf->bv_resid = buf->bv->bv_len; buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; } - skb = skb_prepare(d, f); - if (skb) { - skb->next = NULL; - if (d->sendq_hd) - d->sendq_tl->next = skb; - else - d->sendq_hd = skb; - d->sendq_tl = skb; - } + skb->dev = d->ifp; + skb = skb_clone(skb, GFP_ATOMIC); + if (skb == NULL) + return; + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; } /* some callers cannot sleep, and they can call this function, @@ -209,11 +201,12 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) if (!is_aoe_netif(ifp)) continue; - skb = new_skb(ifp, sizeof *h + sizeof *ch); + skb = new_skb(sizeof *h + sizeof *ch); if (skb == NULL) { - printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n"); + printk(KERN_INFO "aoe: skb alloc failure\n"); continue; } + skb->dev = ifp; if (sl_tail == NULL) sl_tail = skb; h = (struct aoe_hdr *) skb->mac.raw; @@ -237,6 +230,29 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) return sl; } +static struct frame * +freeframe(struct aoedev *d) +{ + struct frame *f, *e; + int n = 0; + + f = d->frames; + e = f + d->nframes; + for (; f<e; f++) { + if (f->tag != FREETAG) + continue; + if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { + skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; + return f; + } + n++; + } + if (n == d->nframes) /* wait for network layer */ + d->flags |= DEVFL_KICKME; + + return NULL; +} + /* enters with d->lock held */ void aoecmd_work(struct aoedev *d) @@ -252,7 +268,7 @@ aoecmd_work(struct aoedev *d) } loop: - f = getframe(d, FREETAG); + f = freeframe(d); if (f == NULL) return; if (d->inprocess == NULL) { @@ -260,7 +276,7 @@ loop: return; buf = container_of(d->bufq.next, struct buf, bufs); list_del(d->bufq.next); -/*printk(KERN_INFO "aoecmd_work: bi_size=%ld\n", buf->bio->bi_size); */ +/*printk(KERN_DEBUG "aoe: bi_size=%ld\n", buf->bio->bi_size); */ d->inprocess = buf; } aoecmd_ata_rw(d, f); @@ -272,6 +288,7 @@ rexmit(struct aoedev *d, struct frame *f) { struct sk_buff *skb; struct aoe_hdr *h; + struct aoe_atahdr *ah; char buf[128]; u32 n; @@ -283,21 +300,41 @@ rexmit(struct aoedev *d, struct frame *f) d->aoemajor, d->aoeminor, f->tag, jiffies, n); aoechr_error(buf); - h = (struct aoe_hdr *) f->data; + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; + ah = (struct aoe_atahdr *) (h+1); f->tag = n; h->tag = cpu_to_be32(n); memcpy(h->dst, d->addr, sizeof h->dst); memcpy(h->src, d->ifp->dev_addr, sizeof h->src); - skb = skb_prepare(d, f); - if (skb) { - skb->next = NULL; - if (d->sendq_hd) - d->sendq_tl->next = skb; - else - d->sendq_hd = skb; - d->sendq_tl = skb; + n = DEFAULTBCNT / 512; + if (ah->scnt > n) { + ah->scnt = n; + if (ah->aflags & AOEAFL_WRITE) { + skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), + offset_in_page(f->bufaddr), DEFAULTBCNT); + skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT; + skb->data_len = DEFAULTBCNT; + } + if (++d->lostjumbo > (d->nframes << 1)) + if (d->maxbcnt != DEFAULTBCNT) { + printk(KERN_INFO "aoe: e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", + d->aoemajor, d->aoeminor, d->ifp->name); + d->maxbcnt = DEFAULTBCNT; + d->flags |= DEVFL_MAXBCNT; + } } + + skb->dev = d->ifp; + skb = skb_clone(skb, GFP_ATOMIC); + if (skb == NULL) + return; + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; } static int @@ -340,13 +377,17 @@ rexmit_timer(ulong vp) if (f->tag != FREETAG && tsince(f->tag) >= timeout) { n = f->waited += timeout; n /= HZ; - if (n > MAXWAIT) { /* waited too long. device failure. */ + if (n > aoe_deadsecs) { /* waited too long for response */ aoedev_downdev(d); break; } rexmit(d, f); } } + if (d->flags & DEVFL_KICKME) { + d->flags &= ~DEVFL_KICKME; + aoecmd_work(d); + } sl = d->sendq_hd; d->sendq_hd = d->sendq_tl = NULL; @@ -431,8 +472,8 @@ ataid_complete(struct aoedev *d, unsigned char *id) } if (d->ssize != ssize) - printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu " - "sectors\n", (unsigned long long)mac_addr(d->addr), + printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n", + (unsigned long long)mac_addr(d->addr), d->aoemajor, d->aoeminor, d->fw_ver, (long long)ssize); d->ssize = ssize; @@ -442,11 +483,9 @@ ataid_complete(struct aoedev *d, unsigned char *id) d->flags |= DEVFL_NEWSIZE; } else { if (d->flags & DEVFL_GDALLOC) { - printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n", - __FUNCTION__, - "can't schedule work for", + printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n", d->aoemajor, d->aoeminor, - "it's already on! (This really shouldn't happen).\n"); + "it's already on! This shouldn't happen.\n"); return; } d->flags |= DEVFL_GDALLOC; @@ -460,8 +499,15 @@ calc_rttavg(struct aoedev *d, int rtt) register long n; n = rtt; - if (n < MINTIMER) - n = MINTIMER; + if (n < 0) { + n = -rtt; + if (n < MINTIMER) + n = MINTIMER; + else if (n > MAXTIMER) + n = MAXTIMER; + d->mintimer += (n - d->mintimer) >> 1; + } else if (n < d->mintimer) + n = d->mintimer; else if (n > MAXTIMER) n = MAXTIMER; @@ -474,7 +520,7 @@ void aoecmd_ata_rsp(struct sk_buff *skb) { struct aoedev *d; - struct aoe_hdr *hin; + struct aoe_hdr *hin, *hout; struct aoe_atahdr *ahin, *ahout; struct frame *f; struct buf *buf; @@ -497,8 +543,10 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - f = getframe(d, be32_to_cpu(hin->tag)); + n = be32_to_cpu(hin->tag); + f = getframe(d, n); if (f == NULL) { + calc_rttavg(d, -tsince(n)); spin_unlock_irqrestore(&d->lock, flags); snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", @@ -514,26 +562,27 @@ aoecmd_ata_rsp(struct sk_buff *skb) calc_rttavg(d, tsince(f->tag)); ahin = (struct aoe_atahdr *) (hin+1); - ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr)); + hout = (struct aoe_hdr *) f->skb->mac.raw; + ahout = (struct aoe_atahdr *) (hout+1); buf = f->buf; if (ahout->cmdstat == WIN_IDENTIFY) d->flags &= ~DEVFL_PAUSE; if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ - printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh " - "stat=%2.2Xh from e%ld.%ld\n", + printk(KERN_ERR + "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n", ahout->cmdstat, ahin->cmdstat, d->aoemajor, d->aoeminor); if (buf) buf->flags |= BUFFL_FAIL; } else { + n = ahout->scnt << 9; switch (ahout->cmdstat) { case WIN_READ: case WIN_READ_EXT: - n = ahout->scnt << 9; if (skb->len - sizeof *hin - sizeof *ahin < n) { - printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt " - "ata data size in read. skb->len=%d\n", + printk(KERN_ERR + "aoe: runt data size in read. skb->len=%d\n", skb->len); /* fail frame f? just returning will rexmit. */ spin_unlock_irqrestore(&d->lock, flags); @@ -542,22 +591,49 @@ aoecmd_ata_rsp(struct sk_buff *skb) memcpy(f->bufaddr, ahin+1, n); case WIN_WRITE: case WIN_WRITE_EXT: + if (f->bcnt -= n) { + skb = f->skb; + f->bufaddr += n; + put_lba(ahout, f->lba += ahout->scnt); + n = f->bcnt; + if (n > DEFAULTBCNT) + n = DEFAULTBCNT; + ahout->scnt = n >> 9; + if (ahout->aflags & AOEAFL_WRITE) { + skb_fill_page_desc(skb, 0, + virt_to_page(f->bufaddr), + offset_in_page(f->bufaddr), n); + skb->len = sizeof *hout + sizeof *ahout + n; + skb->data_len = n; + } + f->tag = newtag(d); + hout->tag = cpu_to_be32(f->tag); + skb->dev = d->ifp; + skb = skb_clone(skb, GFP_ATOMIC); + spin_unlock_irqrestore(&d->lock, flags); + if (skb) + aoenet_xmit(skb); + return; + } + if (n > DEFAULTBCNT) + d->lostjumbo = 0; break; case WIN_IDENTIFY: if (skb->len - sizeof *hin - sizeof *ahin < 512) { - printk(KERN_INFO "aoe: aoecmd_ata_rsp: runt data size " - "in ataid. skb->len=%d\n", skb->len); + printk(KERN_INFO + "aoe: runt data size in ataid. skb->len=%d\n", + skb->len); spin_unlock_irqrestore(&d->lock, flags); return; } ataid_complete(d, (char *) (ahin+1)); break; default: - printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized " - "outbound ata command %2.2Xh for %d.%d\n", - ahout->cmdstat, - be16_to_cpu(hin->major), - hin->minor); + printk(KERN_INFO + "aoe: unrecognized ata command %2.2Xh for %d.%d\n", + ahout->cmdstat, + be16_to_cpu(hin->major), + hin->minor); } } @@ -612,33 +688,32 @@ aoecmd_ata_id(struct aoedev *d) struct frame *f; struct sk_buff *skb; - f = getframe(d, FREETAG); + f = freeframe(d); if (f == NULL) { - printk(KERN_CRIT "aoe: aoecmd_ata_id: can't get a frame. " - "This shouldn't happen.\n"); + printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n"); return NULL; } /* initialize the headers & frame */ - h = (struct aoe_hdr *) f->data; + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - f->ndata = sizeof *h + sizeof *ah; - memset(h, 0, f->ndata); + skb->len = ETH_ZLEN; + memset(h, 0, ETH_ZLEN); f->tag = aoehdr_atainit(d, h); f->waited = 0; - f->writedatalen = 0; /* set up ata header */ ah->scnt = 1; ah->cmdstat = WIN_IDENTIFY; ah->lba3 = 0xa0; - skb = skb_prepare(d, f); + skb->dev = d->ifp; d->rttavg = MAXTIMER; d->timer.function = rexmit_timer; - return skb; + return skb_clone(skb, GFP_ATOMIC); } void @@ -648,9 +723,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb) struct aoe_hdr *h; struct aoe_cfghdr *ch; ulong flags, sysminor, aoemajor; - u16 bufcnt; struct sk_buff *sl; enum { MAXFRAMES = 16 }; + u16 n; h = (struct aoe_hdr *) skb->mac.raw; ch = (struct aoe_cfghdr *) (h+1); @@ -661,26 +736,25 @@ aoecmd_cfg_rsp(struct sk_buff *skb) */ aoemajor = be16_to_cpu(h->major); if (aoemajor == 0xfff) { - printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf " - "address is all ones. Check shelf dip switches\n"); + printk(KERN_ERR "aoe: Warning: shelf address is all ones. " + "Check shelf dip switches.\n"); return; } sysminor = SYSMINOR(aoemajor, h->minor); if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { - printk(KERN_INFO - "aoe: e%ld.%d: minor number too large\n", + printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", aoemajor, (int) h->minor); return; } - bufcnt = be16_to_cpu(ch->bufcnt); - if (bufcnt > MAXFRAMES) /* keep it reasonable */ - bufcnt = MAXFRAMES; + n = be16_to_cpu(ch->bufcnt); + if (n > MAXFRAMES) /* keep it reasonable */ + n = MAXFRAMES; - d = aoedev_by_sysminor_m(sysminor, bufcnt); + d = aoedev_by_sysminor_m(sysminor, n); if (d == NULL) { - printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n"); + printk(KERN_INFO "aoe: device sysminor_m failure\n"); return; } @@ -689,6 +763,20 @@ aoecmd_cfg_rsp(struct sk_buff *skb) /* permit device to migrate mac and network interface */ d->ifp = skb->dev; memcpy(d->addr, h->src, sizeof d->addr); + if (!(d->flags & DEVFL_MAXBCNT)) { + n = d->ifp->mtu; + n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); + n /= 512; + if (n > ch->scnt) + n = ch->scnt; + n = n ? n * 512 : DEFAULTBCNT; + if (n != d->maxbcnt) { + printk(KERN_INFO + "aoe: e%ld.%ld: setting %d byte data frames on %s\n", + d->aoemajor, d->aoeminor, n, d->ifp->name); + d->maxbcnt = n; + } + } /* don't change users' perspective */ if (d->nopen && !(d->flags & DEVFL_PAUSE)) { @@ -696,6 +784,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) return; } d->flags |= DEVFL_PAUSE; /* force pause */ + d->mintimer = MINTIMER; d->fw_ver = be16_to_cpu(ch->fwver); /* check for already outstanding ataid */ diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index ed4258a62df..6125921bbec 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoedev.c * AoE device utility functions; maintains device list. @@ -20,11 +20,8 @@ aoedev_isbusy(struct aoedev *d) f = d->frames; e = f + d->nframes; do { - if (f->tag != FREETAG) { - printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n", - d->aoemajor, d->aoeminor); + if (f->tag != FREETAG) return 1; - } } while (++f < e); return 0; @@ -66,22 +63,32 @@ aoedev_newdev(ulong nframes) struct frame *f, *e; d = kzalloc(sizeof *d, GFP_ATOMIC); - if (d == NULL) - return NULL; f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); - if (f == NULL) { - kfree(d); + switch (!d || !f) { + case 0: + d->nframes = nframes; + d->frames = f; + e = f + nframes; + for (; f<e; f++) { + f->tag = FREETAG; + f->skb = new_skb(ETH_ZLEN); + if (!f->skb) + break; + } + if (f == e) + break; + while (f > d->frames) { + f--; + dev_kfree_skb(f->skb); + } + default: + if (f) + kfree(f); + if (d) + kfree(d); return NULL; } - INIT_WORK(&d->work, aoecmd_sleepwork, d); - - d->nframes = nframes; - d->frames = f; - e = f + nframes; - for (; f<e; f++) - f->tag = FREETAG; - spin_lock_init(&d->lock); init_timer(&d->timer); d->timer.data = (ulong) d; @@ -114,6 +121,7 @@ aoedev_downdev(struct aoedev *d) mempool_free(buf, d->bufpool); bio_endio(bio, bio->bi_size, -EIO); } + skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; } d->inprocess = NULL; @@ -148,7 +156,7 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) d = aoedev_newdev(bufcnt); if (d == NULL) { spin_unlock_irqrestore(&devlist_lock, flags); - printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); + printk(KERN_INFO "aoe: aoedev_newdev failure.\n"); return NULL; } d->sysminor = sysminor; @@ -163,11 +171,19 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) static void aoedev_freedev(struct aoedev *d) { + struct frame *f, *e; + if (d->gd) { aoedisk_rm_sysfs(d); del_gendisk(d->gd); put_disk(d->gd); } + f = d->frames; + e = f + d->nframes; + for (; f<e; f++) { + skb_shinfo(f->skb)->nr_frags = 0; + dev_kfree_skb(f->skb); + } kfree(d->frames); if (d->bufpool) mempool_destroy(d->bufpool); diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c index de08491ebe6..a04b7d61329 100644 --- a/drivers/block/aoe/aoemain.c +++ b/drivers/block/aoe/aoemain.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoemain.c * Module initialization routines, discover timer @@ -84,13 +84,11 @@ aoe_init(void) goto net_fail; ret = register_blkdev(AOE_MAJOR, DEVICE_NAME); if (ret < 0) { - printk(KERN_ERR "aoe: aoeblk_init: can't register major\n"); + printk(KERN_ERR "aoe: can't register major\n"); goto blkreg_fail; } - printk(KERN_INFO - "aoe: aoe_init: AoE v%s initialised.\n", - VERSION); + printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION); discover_timer(TINIT); return 0; @@ -103,7 +101,7 @@ aoe_init(void) chr_fail: aoedev_exit(); - printk(KERN_INFO "aoe: aoe_init: initialisation failure.\n"); + printk(KERN_INFO "aoe: initialisation failure.\n"); return ret; } diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index c1434ed1188..9626e0f5da9 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoenet.c * Ethernet portion of AoE driver @@ -74,7 +74,7 @@ set_aoe_iflist(const char __user *user_str, size_t size) return -EINVAL; if (copy_from_user(aoe_iflist, user_str, size)) { - printk(KERN_INFO "aoe: %s: copy from user failed\n", __FUNCTION__); + printk(KERN_INFO "aoe: copy from user failed\n"); return -EFAULT; } aoe_iflist[size] = 0x00; @@ -132,8 +132,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, if (n > NECODES) n = 0; if (net_ratelimit()) - printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; " - "ecode=%d '%s'\n", + printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n", be16_to_cpu(h->major), h->minor, h->err, aoe_errlist[n]); goto exit; @@ -147,7 +146,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, aoecmd_cfg_rsp(skb); break; default: - printk(KERN_INFO "aoe: aoenet_rcv: unknown cmd %d\n", h->cmd); + printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd); } exit: dev_kfree_skb(skb); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index dcccaf2782f..4105c3bf347 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1300,6 +1300,12 @@ static void cciss_softirq_done(struct request *rq) complete_buffers(rq->bio, rq->errors); + if (blk_fs_request(rq)) { + const int rw = rq_data_dir(rq); + + disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors); + } + #ifdef CCISS_DEBUG printk("Done with %p\n", rq); #endif /* CCISS_DEBUG */ @@ -1923,7 +1929,6 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, { int return_code; unsigned long t; - unsigned long rem; memset(inq_buff, 0, sizeof(InquiryData_struct)); if (withirq) @@ -1939,26 +1944,23 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, printk(KERN_WARNING "cciss: reading geometry failed, volume " "does not support reading geometry\n"); - drv->block_size = block_size; - drv->nr_blocks = total_size; drv->heads = 255; drv->sectors = 32; // Sectors per track - t = drv->heads * drv->sectors; - drv->cylinders = total_size; - rem = do_div(drv->cylinders, t); } else { - drv->block_size = block_size; - drv->nr_blocks = total_size; drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8; drv->cylinders += inq_buff->data_byte[5]; drv->raid_level = inq_buff->data_byte[8]; - t = drv->heads * drv->sectors; - if (t > 1) { - drv->cylinders = total_size; - rem = do_div(drv->cylinders, t); - } + } + drv->block_size = block_size; + drv->nr_blocks = total_size; + t = drv->heads * drv->sectors; + if (t > 1) { + unsigned rem = sector_div(total_size, t); + if (rem) + total_size++; + drv->cylinders = total_size; } } else { /* Get geometry failed */ printk(KERN_WARNING "cciss: reading geometry failed\n"); @@ -1996,8 +1998,8 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, *block_size = BLOCK_SIZE; } if (*total_size != (__u32) 0) - printk(KERN_INFO " blocks= %lld block_size= %d\n", - *total_size, *block_size); + printk(KERN_INFO " blocks= %llu block_size= %d\n", + (unsigned long long)*total_size, *block_size); kfree(buf); return; } @@ -2031,8 +2033,8 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, *total_size = 0; *block_size = BLOCK_SIZE; } - printk(KERN_INFO " blocks= %lld block_size= %d\n", - *total_size, *block_size); + printk(KERN_INFO " blocks= %llu block_size= %d\n", + (unsigned long long)*total_size, *block_size); kfree(buf); return; } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 570d2f04932..d5f519ebbc0 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -998,6 +998,7 @@ static inline void complete_buffers(struct bio *bio, int ok) */ static inline void complete_command(cmdlist_t *cmd, int timeout) { + struct request *rq = cmd->rq; int ok=1; int i, ddir; @@ -1029,12 +1030,18 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) pci_unmap_page(hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr, cmd->req.sg[i].size, ddir); - complete_buffers(cmd->rq->bio, ok); + complete_buffers(rq->bio, ok); - add_disk_randomness(cmd->rq->rq_disk); + if (blk_fs_request(rq)) { + const int rw = rq_data_dir(rq); - DBGPX(printk("Done with %p\n", cmd->rq);); - end_that_request_last(cmd->rq, ok ? 1 : -EIO); + disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors); + } + + add_disk_randomness(rq->rq_disk); + + DBGPX(printk("Done with %p\n", rq);); + end_that_request_last(rq, ok ? 1 : -EIO); } /* diff --git a/drivers/block/rd.c b/drivers/block/rd.c index a3f64bfe6b5..485aa87e9bc 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -432,6 +432,12 @@ static int __init rd_init(void) rd_disks[i] = alloc_disk(1); if (!rd_disks[i]) goto out; + + rd_queue[i] = blk_alloc_queue(GFP_KERNEL); + if (!rd_queue[i]) { + put_disk(rd_disks[i]); + goto out; + } } if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) { @@ -442,10 +448,6 @@ static int __init rd_init(void) for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) { struct gendisk *disk = rd_disks[i]; - rd_queue[i] = blk_alloc_queue(GFP_KERNEL); - if (!rd_queue[i]) - goto out_queue; - blk_queue_make_request(rd_queue[i], &rd_make_request); blk_queue_hardsect_size(rd_queue[i], rd_blocksize); @@ -466,8 +468,6 @@ static int __init rd_init(void) CONFIG_BLK_DEV_RAM_COUNT, rd_size, rd_blocksize); return 0; -out_queue: - unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); out: while (i--) { put_disk(rd_disks[i]); diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 10cc38783bd..0d97b7eb818 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -48,9 +48,9 @@ #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/delay.h> +#include <linux/io.h> #include <asm/system.h> -#include <asm/io.h> #include <asm/uaccess.h> #include <asm/dma.h> diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 82ddbdd7bd4..7cc2685ca84 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -329,7 +329,7 @@ static struct kobject *z2_find(dev_t dev, int *part, void *data) static struct request_queue *z2_queue; -int __init +static int __init z2_init(void) { int ret; @@ -370,26 +370,7 @@ err: return ret; } -#if defined(MODULE) - -MODULE_LICENSE("GPL"); - -int -init_module( void ) -{ - int error; - - error = z2_init(); - if ( error == 0 ) - { - printk( KERN_INFO DEVICE_NAME ": loaded as module\n" ); - } - - return error; -} - -void -cleanup_module( void ) +static void __exit z2_exit(void) { int i, j; blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256); @@ -425,4 +406,7 @@ cleanup_module( void ) return; } -#endif + +module_init(z2_init); +module_exit(z2_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 67cdda43f22..516751754aa 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/errno.h> -#include <linux/timer.h> #include <linux/device.h> #include <linux/firmware.h> @@ -43,7 +42,7 @@ #define BT_DBG(D...) #endif -#define VERSION "1.0" +#define VERSION "1.1" static int ignore = 0; @@ -72,7 +71,7 @@ struct bcm203x_data { unsigned long state; - struct timer_list timer; + struct work_struct work; struct urb *urb; unsigned char *buffer; @@ -105,7 +104,7 @@ static void bcm203x_complete(struct urb *urb) data->state = BCM203X_SELECT_MEMORY; - mod_timer(&data->timer, jiffies + (HZ / 10)); + schedule_work(&data->work); break; case BCM203X_SELECT_MEMORY: @@ -158,9 +157,9 @@ static void bcm203x_complete(struct urb *urb) } } -static void bcm203x_timer(unsigned long user_data) +static void bcm203x_work(void *user_data) { - struct bcm203x_data *data = (struct bcm203x_data *) user_data; + struct bcm203x_data *data = user_data; if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) BT_ERR("Can't submit URB"); @@ -247,13 +246,11 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id release_firmware(firmware); - init_timer(&data->timer); - data->timer.function = bcm203x_timer; - data->timer.data = (unsigned long) data; + INIT_WORK(&data->work, bcm203x_work, (void *) data); usb_set_intfdata(intf, data); - mod_timer(&data->timer, jiffies + HZ); + schedule_work(&data->work); return 0; } diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 845b8680032..cbc07250b89 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -282,7 +282,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info) clear_bit(ready_bit, &(info->tx_state)); if (bt_cb(skb)->pkt_type & 0x80) { - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); DEFINE_WAIT(wait); unsigned char baud_reg; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index e7c800f4c3a..07eafbc5dc3 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -711,6 +711,7 @@ static void dtl1_release(struct pcmcia_device *link) static struct pcmcia_device_id dtl1_ids[] = { PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d), + PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82), PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863), PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3), PCMCIA_DEVICE_NULL diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 7565642a007..fdea58ae16b 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -118,6 +118,9 @@ static struct usb_device_id blacklist_ids[] = { /* IBM/Lenovo ThinkPad with Broadcom chip */ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU }, + /* ANYCOM Bluetooth USB-200 and USB-250 */ + { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, + /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 0e6f35fcc2e..2af12fc4511 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -409,14 +409,6 @@ config SGI_MBCS If you have an SGI Altix with an attached SABrick say Y or M here, otherwise say N. -config MSPEC - tristate "Memory special operations driver" - depends on IA64 - help - If you have an ia64 and you want to enable memory special - operations support (formerly known as fetchop), say Y here, - otherwise say N. - source "drivers/serial/Kconfig" config UNIX98_PTYS @@ -1046,7 +1038,7 @@ source "drivers/char/tpm/Kconfig" config TELCLOCK tristate "Telecom clock driver for MPBL0010 ATCA SBC" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && X86 default n help The telecom clock device is specific to the MPBL0010 ATCA computer and diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 91b71e750ee..dffc19382f7 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -27,32 +27,42 @@ static int uninorth_rev; static int is_u3; +static char __devinitdata *aperture = NULL; static int uninorth_fetch_size(void) { - int i; - u32 temp; - struct aper_size_info_32 *values; - - pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp); - temp &= ~(0xfffff000); - values = A_SIZE_32(agp_bridge->driver->aperture_sizes); - - for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { - if (temp == values[i].size_value) { - agp_bridge->previous_size = - agp_bridge->current_size = (void *) (values + i); - agp_bridge->aperture_size_idx = i; - return values[i].size; + int i, size = 0; + struct aper_size_info_32 *values = + A_SIZE_32(agp_bridge->driver->aperture_sizes); + + if (aperture) { + char *save = aperture; + + size = memparse(aperture, &aperture) >> 20; + aperture = save; + + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) + if (size == values[i].size) + break; + + if (i == agp_bridge->driver->num_aperture_sizes) { + printk(KERN_ERR PFX "Invalid aperture size, using" + " default\n"); + size = 0; + aperture = NULL; } } - agp_bridge->previous_size = - agp_bridge->current_size = (void *) (values + 1); - agp_bridge->aperture_size_idx = 1; - return values[1].size; + if (!size) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) + if (values[i].size == 32) + break; + } - return 0; + agp_bridge->previous_size = + agp_bridge->current_size = (void *)(values + i); + agp_bridge->aperture_size_idx = i; + return values[i].size; } static void uninorth_tlbflush(struct agp_memory *mem) @@ -683,5 +693,11 @@ static void __exit agp_uninorth_cleanup(void) module_init(agp_uninorth_init); module_exit(agp_uninorth_cleanup); +module_param(aperture, charp, 0); +MODULE_PARM_DESC(aperture, + "Aperture size, must be power of two between 4MB and an\n" + "\t\tupper limit specific to the UniNorth revision.\n" + "\t\tDefault: 32M"); + MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 029baea33b6..6eafff13dab 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -237,6 +237,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); if (!list) { + if (map->type == _DRM_REGISTERS) + drm_ioremapfree(map->handle, map->size, dev); drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; } @@ -252,6 +254,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, map->offset; ret = drm_map_handle(dev, &list->hash, user_token, 0); if (ret) { + if (map->type == _DRM_REGISTERS) + drm_ioremapfree(map->handle, map->size, dev); drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(list, sizeof(*list), DRM_MEM_MAPS); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 51ad98c685c..ba4b8de83cf 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -42,13 +42,24 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL); struct class *drm_sysfs_create(struct module *owner, char *name) { struct class *class; + int err; class = class_create(owner, name); - if (!class) - return class; + if (!class) { + err = -ENOMEM; + goto err_out; + } + + err = class_create_file(class, &class_attr_version); + if (err) + goto err_out_class; - class_create_file(class, &class_attr_version); return class; + +err_out_class: + class_destroy(class); +err_out: + return ERR_PTR(err); } /** @@ -96,20 +107,36 @@ static struct class_device_attribute class_device_attrs[] = { struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head) { struct class_device *class_dev; - int i; + int i, j, err; class_dev = class_device_create(cs, NULL, MKDEV(DRM_MAJOR, head->minor), &(head->dev->pdev)->dev, "card%d", head->minor); - if (!class_dev) - return NULL; + if (!class_dev) { + err = -ENOMEM; + goto err_out; + } class_set_devdata(class_dev, head); - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_create_file(class_dev, &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { + err = class_device_create_file(class_dev, + &class_device_attrs[i]); + if (err) + goto err_out_files; + } + return class_dev; + +err_out_files: + if (i > 0) + for (j = 0; j < i; j++) + class_device_remove_file(class_dev, + &class_device_attrs[i]); + class_device_unregister(class_dev); +err_out: + return ERR_PTR(err); } /** diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index e30f556b79f..be49dbb9ec3 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -47,6 +47,7 @@ static struct drm_driver driver = { DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + .dev_priv_size = sizeof(drm_mga_buf_priv_t), .load = mga_driver_load, .unload = mga_driver_unload, .lastclose = mga_driver_lastclose, diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index 26bdf2ca59d..d14477ba367 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, return 0; } +static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) +{ + u32 *cmd = (u32 *) cmdbuf->buf; + int count, ret; + RING_LOCALS; + + count=(cmd[0]>>16) & 0x3fff; + + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return DRM_ERR(EINVAL); + } + ret = r300_check_offset(dev_priv, cmd[2]); + if (ret) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return DRM_ERR(EINVAL); + } + + BEGIN_RING(count+2); + OUT_RING(cmd[0]); + OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1); + ADVANCE_RING(); + + cmdbuf->buf += (count+2)*4; + cmdbuf->bufsz -= (count+2)*4; + + return 0; +} + static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, drm_radeon_kcmd_buffer_t *cmdbuf) { @@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, case RADEON_CNTL_BITBLT_MULTI: return r300_emit_bitblt_multi(dev_priv, cmdbuf); + case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ + return r300_emit_indx_buffer(dev_priv, cmdbuf); case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ - case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: /* these packets are safe */ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index feac5f005d4..6e04fdd732a 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * unsigned int *cmdsz) { u32 *cmd = (u32 *) cmdbuf->buf; + u32 offset, narrays; + int count, i, k; *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); @@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * return DRM_ERR(EINVAL); } - /* Check client state and fix it up if necessary */ - if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */ - u32 offset; + switch(cmd[0] & 0xff00) { + /* XXX Are there old drivers needing other packets? */ + case RADEON_3D_DRAW_IMMD: + case RADEON_3D_DRAW_VBUF: + case RADEON_3D_DRAW_INDX: + case RADEON_WAIT_FOR_IDLE: + case RADEON_CP_NOP: + case RADEON_3D_CLEAR_ZMASK: +/* case RADEON_CP_NEXT_CHAR: + case RADEON_CP_PLY_NEXTSCAN: + case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ + /* these packets are safe */ + break; + + case RADEON_CP_3D_DRAW_IMMD_2: + case RADEON_CP_3D_DRAW_VBUF_2: + case RADEON_CP_3D_DRAW_INDX_2: + case RADEON_3D_CLEAR_HIZ: + /* safe but r200 only */ + if (dev_priv->microcode_version != UCODE_R200) { + DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_3D_LOAD_VBPNTR: + count = (cmd[0] >> 16) & 0x3fff; + + if (count > 18) { /* 12 arrays max */ + DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", + count); + return DRM_ERR(EINVAL); + } + + /* carefully check packet contents */ + narrays = cmd[1] & ~0xc000; + k = 0; + i = 2; + while ((k < narrays) && (i < (count + 2))) { + i++; /* skip attribute field */ + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + DRM_ERROR + ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", + k, i); + return DRM_ERR(EINVAL); + } + k++; + i++; + if (k == narrays) + break; + /* have one more to process, they come in pairs */ + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + DRM_ERROR + ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", + k, i); + return DRM_ERR(EINVAL); + } + k++; + i++; + } + /* do the counts match what we expect ? */ + if ((k != narrays) || (i != (count + 2))) { + DRM_ERROR + ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", + k, i, narrays, count + 1); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_3D_RNDR_GEN_INDX_PRIM: + if (dev_priv->microcode_version != UCODE_R100) { + DRM_ERROR("Invalid 3d packet for r200-class chip\n"); + return DRM_ERR(EINVAL); + } + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) { + DRM_ERROR("Invalid rndr_gen_indx offset\n"); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_CP_INDX_BUFFER: + if (dev_priv->microcode_version != UCODE_R200) { + DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + return DRM_ERR(EINVAL); + } + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return DRM_ERR(EINVAL); + } + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_CNTL_HOSTDATA_BLT: + case RADEON_CNTL_PAINT_MULTI: + case RADEON_CNTL_BITBLT_MULTI: + /* MSB of opcode: next DWORD GUI_CNTL */ if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[2] << 10; @@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * } cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; } + break; + + default: + DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); + return DRM_ERR(EINVAL); } return 0; diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index 59c7520bf9a..a9a84f88df5 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -728,6 +728,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init) dev_priv->status = NULL; } if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) { + dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c index ef2581d1614..1ca1e9cb5a3 100644 --- a/drivers/char/drm/savage_state.c +++ b/drivers/char/drm/savage_state.c @@ -994,7 +994,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) if (cmdbuf.size) { kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); if (kcmd_addr == NULL) - return ENOMEM; + return DRM_ERR(ENOMEM); if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, cmdbuf.size * 8)) diff --git a/drivers/char/epca.c b/drivers/char/epca.c index c3f95583a12..706733c0b36 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1157,6 +1157,7 @@ static int __init pc_init(void) int crd; struct board_info *bd; unsigned char board_id = 0; + int err = -ENOMEM; int pci_boards_found, pci_count; @@ -1164,13 +1165,11 @@ static int __init pc_init(void) pc_driver = alloc_tty_driver(MAX_ALLOC); if (!pc_driver) - return -ENOMEM; + goto out1; pc_info = alloc_tty_driver(MAX_ALLOC); - if (!pc_info) { - put_tty_driver(pc_driver); - return -ENOMEM; - } + if (!pc_info) + goto out2; /* ----------------------------------------------------------------------- If epca_setup has not been ran by LILO set num_cards to defaults; copy @@ -1370,11 +1369,17 @@ static int __init pc_init(void) } /* End for each card */ - if (tty_register_driver(pc_driver)) - panic("Couldn't register Digi PC/ driver"); + err = tty_register_driver(pc_driver); + if (err) { + printk(KERN_ERR "Couldn't register Digi PC/ driver"); + goto out3; + } - if (tty_register_driver(pc_info)) - panic("Couldn't register Digi PC/ info "); + err = tty_register_driver(pc_info); + if (err) { + printk(KERN_ERR "Couldn't register Digi PC/ info "); + goto out4; + } /* ------------------------------------------------------------------- Start up the poller to check for events on all enabled boards @@ -1385,6 +1390,15 @@ static int __init pc_init(void) mod_timer(&epca_timer, jiffies + HZ/25); return 0; +out4: + tty_unregister_driver(pc_driver); +out3: + put_tty_driver(pc_info); +out2: + put_tty_driver(pc_driver); +out1: + return err; + } /* End pc_init */ /* ------------------ Begin post_fep_init ---------------------- */ diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c index da06f138334..7ebce2ec789 100644 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ b/drivers/char/ftape/zftape/zftape-buffers.c @@ -85,7 +85,7 @@ int zft_vmalloc_once(void *new, size_t size) peak_memory = used_memory; } TRACE_ABORT(0, ft_t_noise, - "allocated buffer @ %p, %d bytes", *(void **)new, size); + "allocated buffer @ %p, %zd bytes", *(void **)new, size); } int zft_vmalloc_always(void *new, size_t size) { @@ -101,7 +101,7 @@ void zft_vfree(void *old, size_t size) if (*(void **)old) { vfree(*(void **)old); used_memory -= size; - TRACE(ft_t_noise, "released buffer @ %p, %d bytes", + TRACE(ft_t_noise, "released buffer @ %p, %zd bytes", *(void **)old, size); *(void **)old = NULL; } diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index fc944d375be..54d93f0345e 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -1007,7 +1007,7 @@ i2InputAvailable(i2ChanStrPtr pCh) // applications that one cannot break out of. //****************************************************************************** static int -i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) +i2Output(i2ChanStrPtr pCh, const char *pSource, int count) { i2eBordStrPtr pB; unsigned char *pInsert; @@ -1020,7 +1020,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) int bailout = 10; - ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user ); + ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, 0 ); // Ensure channel structure seems real if ( !i2Validate ( pCh ) ) @@ -1087,12 +1087,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) DATA_COUNT_OF(pInsert) = amountToMove; // Move the data - if ( user ) { - rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource, - amountToMove ); - } else { - memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); - } + memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); // Adjust pointers and indices pSource += amountToMove; pCh->Obuf_char_count += amountToMove; diff --git a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h index 952e113ccd8..e559e9bac06 100644 --- a/drivers/char/ip2/i2lib.h +++ b/drivers/char/ip2/i2lib.h @@ -332,7 +332,7 @@ static int i2QueueCommands(int, i2ChanStrPtr, int, int, cmdSyntaxPtr,...); static int i2GetStatus(i2ChanStrPtr, int); static int i2Input(i2ChanStrPtr); static int i2InputFlush(i2ChanStrPtr); -static int i2Output(i2ChanStrPtr, const char *, int, int); +static int i2Output(i2ChanStrPtr, const char *, int); static int i2OutputFree(i2ChanStrPtr); static int i2ServiceBoard(i2eBordStrPtr); static void i2DrainOutput(i2ChanStrPtr, int); diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 858ba5432c9..a3f32d46d2f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1704,7 +1704,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count) /* This is the actual move bit. Make sure it does what we need!!!!! */ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); - bytesSent = i2Output( pCh, pData, count, 0 ); + bytesSent = i2Output( pCh, pData, count); WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent ); @@ -1764,7 +1764,7 @@ ip2_flush_chars( PTTY tty ) // // We may need to restart i2Output if it does not fullfill this request // - strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 ); + strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff); if ( strip != pCh->Pbuf_stuff ) { memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip ); } diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 2455e8d478a..c47add8e47d 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -376,13 +376,23 @@ static void free_recv_msg_list(struct list_head *q) } } +static void free_smi_msg_list(struct list_head *q) +{ + struct ipmi_smi_msg *msg, *msg2; + + list_for_each_entry_safe(msg, msg2, q, link) { + list_del(&msg->link); + ipmi_free_smi_msg(msg); + } +} + static void clean_up_interface_data(ipmi_smi_t intf) { int i; struct cmd_rcvr *rcvr, *rcvr2; struct list_head list; - free_recv_msg_list(&intf->waiting_msgs); + free_smi_msg_list(&intf->waiting_msgs); free_recv_msg_list(&intf->waiting_events); /* Wholesale remove all the entries from the list in the @@ -1844,7 +1854,7 @@ static ssize_t provides_dev_sdrs_show(struct device *dev, struct bmc_device *bmc = dev_get_drvdata(dev); return snprintf(buf, 10, "%u\n", - bmc->id.device_revision && 0x80 >> 7); + (bmc->id.device_revision & 0x80) >> 7); } static ssize_t revision_show(struct device *dev, struct device_attribute *attr, @@ -1853,7 +1863,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, struct bmc_device *bmc = dev_get_drvdata(dev); return snprintf(buf, 20, "%u\n", - bmc->id.device_revision && 0x0F); + bmc->id.device_revision & 0x0F); } static ssize_t firmware_rev_show(struct device *dev, @@ -1928,13 +1938,8 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, (long long) bmc->guid[8]); } -static void -cleanup_bmc_device(struct kref *ref) +static void remove_files(struct bmc_device *bmc) { - struct bmc_device *bmc; - - bmc = container_of(ref, struct bmc_device, refcount); - device_remove_file(&bmc->dev->dev, &bmc->device_id_attr); device_remove_file(&bmc->dev->dev, @@ -1951,12 +1956,23 @@ cleanup_bmc_device(struct kref *ref) &bmc->manufacturer_id_attr); device_remove_file(&bmc->dev->dev, &bmc->product_id_attr); + if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); if (bmc->guid_set) device_remove_file(&bmc->dev->dev, &bmc->guid_attr); +} + +static void +cleanup_bmc_device(struct kref *ref) +{ + struct bmc_device *bmc; + + bmc = container_of(ref, struct bmc_device, refcount); + + remove_files(bmc); platform_device_unregister(bmc->dev); kfree(bmc); } @@ -1977,6 +1993,79 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) mutex_unlock(&ipmidriver_mutex); } +static int create_files(struct bmc_device *bmc) +{ + int err; + + err = device_create_file(&bmc->dev->dev, + &bmc->device_id_attr); + if (err) goto out; + err = device_create_file(&bmc->dev->dev, + &bmc->provides_dev_sdrs_attr); + if (err) goto out_devid; + err = device_create_file(&bmc->dev->dev, + &bmc->revision_attr); + if (err) goto out_sdrs; + err = device_create_file(&bmc->dev->dev, + &bmc->firmware_rev_attr); + if (err) goto out_rev; + err = device_create_file(&bmc->dev->dev, + &bmc->version_attr); + if (err) goto out_firm; + err = device_create_file(&bmc->dev->dev, + &bmc->add_dev_support_attr); + if (err) goto out_version; + err = device_create_file(&bmc->dev->dev, + &bmc->manufacturer_id_attr); + if (err) goto out_add_dev; + err = device_create_file(&bmc->dev->dev, + &bmc->product_id_attr); + if (err) goto out_manu; + if (bmc->id.aux_firmware_revision_set) { + err = device_create_file(&bmc->dev->dev, + &bmc->aux_firmware_rev_attr); + if (err) goto out_prod_id; + } + if (bmc->guid_set) { + err = device_create_file(&bmc->dev->dev, + &bmc->guid_attr); + if (err) goto out_aux_firm; + } + + return 0; + +out_aux_firm: + if (bmc->id.aux_firmware_revision_set) + device_remove_file(&bmc->dev->dev, + &bmc->aux_firmware_rev_attr); +out_prod_id: + device_remove_file(&bmc->dev->dev, + &bmc->product_id_attr); +out_manu: + device_remove_file(&bmc->dev->dev, + &bmc->manufacturer_id_attr); +out_add_dev: + device_remove_file(&bmc->dev->dev, + &bmc->add_dev_support_attr); +out_version: + device_remove_file(&bmc->dev->dev, + &bmc->version_attr); +out_firm: + device_remove_file(&bmc->dev->dev, + &bmc->firmware_rev_attr); +out_rev: + device_remove_file(&bmc->dev->dev, + &bmc->revision_attr); +out_sdrs: + device_remove_file(&bmc->dev->dev, + &bmc->provides_dev_sdrs_attr); +out_devid: + device_remove_file(&bmc->dev->dev, + &bmc->device_id_attr); +out: + return err; +} + static int ipmi_bmc_register(ipmi_smi_t intf) { int rv; @@ -2029,7 +2118,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf) dev_set_drvdata(&bmc->dev->dev, bmc); kref_init(&bmc->refcount); - rv = platform_device_register(bmc->dev); + rv = platform_device_add(bmc->dev); mutex_unlock(&ipmidriver_mutex); if (rv) { printk(KERN_ERR @@ -2051,7 +2140,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf) bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; - bmc->revision_attr.attr.name = "revision"; bmc->revision_attr.attr.owner = THIS_MODULE; bmc->revision_attr.attr.mode = S_IRUGO; @@ -2093,28 +2181,14 @@ static int ipmi_bmc_register(ipmi_smi_t intf) bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; - device_create_file(&bmc->dev->dev, - &bmc->device_id_attr); - device_create_file(&bmc->dev->dev, - &bmc->provides_dev_sdrs_attr); - device_create_file(&bmc->dev->dev, - &bmc->revision_attr); - device_create_file(&bmc->dev->dev, - &bmc->firmware_rev_attr); - device_create_file(&bmc->dev->dev, - &bmc->version_attr); - device_create_file(&bmc->dev->dev, - &bmc->add_dev_support_attr); - device_create_file(&bmc->dev->dev, - &bmc->manufacturer_id_attr); - device_create_file(&bmc->dev->dev, - &bmc->product_id_attr); - if (bmc->id.aux_firmware_revision_set) - device_create_file(&bmc->dev->dev, - &bmc->aux_firmware_rev_attr); - if (bmc->guid_set) - device_create_file(&bmc->dev->dev, - &bmc->guid_attr); + rv = create_files(bmc); + if (rv) { + mutex_lock(&ipmidriver_mutex); + platform_device_unregister(bmc->dev); + mutex_unlock(&ipmidriver_mutex); + + return rv; + } printk(KERN_INFO "ipmi: Found new BMC (man_id: 0x%6.6x, " @@ -3168,7 +3242,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, report the error immediately. */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) - && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)) + && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) + && (msg->rsp[2] != IPMI_BUS_ERR) + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int chan = msg->rsp[3] & 0xf; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 24825bdca8f..bb1fac104fd 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1211,7 +1211,7 @@ static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) { return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) - && 0xff; + & 0xff; } static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, @@ -1223,7 +1223,7 @@ static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) { return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) - && 0xff; + & 0xff; } static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, @@ -1236,7 +1236,7 @@ static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) { return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) - && 0xff; + & 0xff; } static void mem_outq(struct si_sm_io *io, unsigned int offset, @@ -1789,7 +1789,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) - return ENOMEM; + return -ENOMEM; info->addr_source = "PCI"; @@ -1810,7 +1810,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, kfree(info); printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n", pci_name(pdev), class_type); - return ENOMEM; + return -ENOMEM; } rv = pci_enable_device(pdev); @@ -1867,7 +1867,7 @@ static int ipmi_pci_resume(struct pci_dev *pdev) static struct pci_device_id ipmi_pci_devices[] = { { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, - { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE) } + { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) } }; MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); @@ -2346,7 +2346,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->dev = &new_smi->pdev->dev; new_smi->dev->driver = &ipmi_driver; - rv = platform_device_register(new_smi->pdev); + rv = platform_device_add(new_smi->pdev); if (rv) { printk(KERN_ERR "ipmi_si_intf:" diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index e9e9bf31c36..58c955e390b 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1062,11 +1062,12 @@ static void isicom_shutdown_port(struct isi_port *port) static void isicom_close(struct tty_struct *tty, struct file *filp) { struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; + struct isi_board *card; unsigned long flags; if (!port) return; + card = port->card; if (isicom_paranoia_check(port, tty->name, "isicom_close")) return; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 6511012cbdc..55473371b7c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -26,6 +26,7 @@ #include <linux/backing-dev.h> #include <linux/bootmem.h> #include <linux/pipe_fs_i.h> +#include <linux/pfn.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -292,8 +293,8 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; - /* Turn a kernel-virtual address into a physical page frame */ - pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; + /* Turn a pfn offset into an absolute pfn */ + pfn = PFN_DOWN(virt_to_phys((void *)PAGE_OFFSET)) + vma->vm_pgoff; /* * RED-PEN: on some architectures there is more mapped memory diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index b401383808c..96cb1f07332 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -130,6 +130,7 @@ static moxa_isa_board_conf moxa_isa_boards[] = typedef struct _moxa_pci_devinfo { ushort busNum; ushort devNum; + struct pci_dev *pdev; } moxa_pci_devinfo; typedef struct _moxa_board_conf { @@ -324,6 +325,9 @@ static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf board->busType = MOXA_BUS_TYPE_PCI; board->pciInfo.busNum = p->bus->number; board->pciInfo.devNum = p->devfn >> 3; + board->pciInfo.pdev = p; + /* don't lose the reference in the next pci_get_device iteration */ + pci_dev_get(p); return (0); } @@ -493,6 +497,11 @@ static void __exit moxa_exit(void) if (tty_unregister_driver(moxaDriver)) printk("Couldn't unregister MOXA Intellio family serial driver\n"); put_tty_driver(moxaDriver); + + for (i = 0; i < MAX_BOARDS; i++) + if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI) + pci_dev_put(moxa_boards[i].pciInfo.pdev); + if (verbose) printk("Done\n"); } diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 5c0dec39cf6..235e8922611 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -72,7 +72,11 @@ enum { MSPEC_UNCACHED }; +#ifdef CONFIG_SGI_SN static int is_sn2; +#else +#define is_sn2 0 +#endif /* * One of these structures is allocated when an mspec region is mmaped. The @@ -211,7 +215,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) if (vdata->type == MSPEC_FETCHOP) paddr = TO_AMO(maddr); else - paddr = __pa(TO_CAC(maddr)); + paddr = maddr & ~__IA64_UNCACHED_OFFSET; pfn = paddr >> PAGE_SHIFT; @@ -335,6 +339,7 @@ mspec_init(void) * The fetchop device only works on SN2 hardware, uncached and cached * memory drivers should both be valid on all ia64 hardware */ +#ifdef CONFIG_SGI_SN if (ia64_platform_is("sn2")) { is_sn2 = 1; if (is_shub2()) { @@ -363,6 +368,7 @@ mspec_init(void) goto free_scratch_pages; } } +#endif ret = misc_register(&cached_miscdev); if (ret) { printk(KERN_ERR "%s: failed to register device %i\n", diff --git a/drivers/char/random.c b/drivers/char/random.c index 07f47a0208a..eb6b13f4211 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -645,6 +645,7 @@ void add_input_randomness(unsigned int type, unsigned int code, add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ value); } +EXPORT_SYMBOL_GPL(add_input_randomness); void add_interrupt_randomness(int irq) { diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index ee2ddea7a63..23d0681fe49 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h @@ -44,6 +44,7 @@ ** the host. */ struct Host { + struct pci_dev *pdev; unsigned char Type; /* RIO_EISA, RIO_MCA, ... */ unsigned char Ivec; /* POLLED or ivec number */ unsigned char Mode; /* Control stuff */ diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index c382df0f82f..7ac68cb3bed 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -1017,6 +1017,10 @@ static int __init rio_init(void) rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum); fix_rio_pci(pdev); + + p->RIOHosts[p->RIONumHosts].pdev = pdev; + pci_dev_get(pdev); + p->RIOLastPCISearch = 0; p->RIONumHosts++; found++; @@ -1066,6 +1070,9 @@ static int __init rio_init(void) ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24); rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum); + p->RIOHosts[p->RIONumHosts].pdev = pdev; + pci_dev_get(pdev); + p->RIOLastPCISearch = 0; p->RIONumHosts++; found++; @@ -1181,6 +1188,8 @@ static void __exit rio_exit(void) } /* It is safe/allowed to del_timer a non-active timer */ del_timer(&hp->timer); + if (hp->Type == RIO_PCI) + pci_dev_put(hp->pdev); } if (misc_deregister(&rio_fw_device) < 0) { diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index 052e8120a47..7ce77619707 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -662,7 +662,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su p->RIOError.Error = COPYIN_FAILED; return -EFAULT; } - if (portStats.port >= RIO_PORTS) { + if (portStats.port < 0 || portStats.port >= RIO_PORTS) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return -ENXIO; } @@ -702,7 +702,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su p->RIOError.Error = COPYIN_FAILED; return -EFAULT; } - if (portStats.port >= RIO_PORTS) { + if (portStats.port < 0 || portStats.port >= RIO_PORTS) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return -ENXIO; } diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 461bfe0234c..3af7f0958c5 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -839,7 +839,7 @@ shutdown(struct cyclades_port * info) local_irq_save(flags); if (info->xmit_buf){ free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; + info->xmit_buf = NULL; } base_addr[CyCAR] = (u_char)channel; @@ -1354,7 +1354,7 @@ cy_unthrottle(struct tty_struct * tty) static int get_serial_info(struct cyclades_port * info, - struct serial_struct * retinfo) + struct serial_struct __user * retinfo) { struct serial_struct tmp; @@ -1376,7 +1376,7 @@ get_serial_info(struct cyclades_port * info, static int set_serial_info(struct cyclades_port * info, - struct serial_struct * new_info) + struct serial_struct __user * new_info) { struct serial_struct new_serial; struct cyclades_port old_info; @@ -1503,7 +1503,7 @@ send_break( struct cyclades_port * info, int duration) } /* send_break */ static int -get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) +get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon) { if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) @@ -1516,7 +1516,7 @@ get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) } static int -set_threshold(struct cyclades_port * info, unsigned long *arg) +set_threshold(struct cyclades_port * info, unsigned long __user *arg) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long value; @@ -1533,7 +1533,7 @@ set_threshold(struct cyclades_port * info, unsigned long *arg) } static int -get_threshold(struct cyclades_port * info, unsigned long *value) +get_threshold(struct cyclades_port * info, unsigned long __user *value) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; @@ -1546,7 +1546,7 @@ get_threshold(struct cyclades_port * info, unsigned long *value) } static int -set_default_threshold(struct cyclades_port * info, unsigned long *arg) +set_default_threshold(struct cyclades_port * info, unsigned long __user *arg) { unsigned long value; @@ -1558,13 +1558,13 @@ set_default_threshold(struct cyclades_port * info, unsigned long *arg) } static int -get_default_threshold(struct cyclades_port * info, unsigned long *value) +get_default_threshold(struct cyclades_port * info, unsigned long __user *value) { return put_user(info->default_threshold,value); } static int -set_timeout(struct cyclades_port * info, unsigned long *arg) +set_timeout(struct cyclades_port * info, unsigned long __user *arg) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; @@ -1581,7 +1581,7 @@ set_timeout(struct cyclades_port * info, unsigned long *arg) } static int -get_timeout(struct cyclades_port * info, unsigned long *value) +get_timeout(struct cyclades_port * info, unsigned long __user *value) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; @@ -1601,7 +1601,7 @@ set_default_timeout(struct cyclades_port * info, unsigned long value) } static int -get_default_timeout(struct cyclades_port * info, unsigned long *value) +get_default_timeout(struct cyclades_port * info, unsigned long __user *value) { return put_user(info->default_timeout,value); } @@ -1613,6 +1613,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file, unsigned long val; struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int ret_val = 0; + void __user *argp = (void __user *)arg; #ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ @@ -1620,28 +1621,28 @@ cy_ioctl(struct tty_struct *tty, struct file * file, switch (cmd) { case CYGETMON: - ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); + ret_val = get_mon_info(info, argp); break; case CYGETTHRESH: - ret_val = get_threshold(info, (unsigned long *)arg); + ret_val = get_threshold(info, argp); break; case CYSETTHRESH: - ret_val = set_threshold(info, (unsigned long *)arg); + ret_val = set_threshold(info, argp); break; case CYGETDEFTHRESH: - ret_val = get_default_threshold(info, (unsigned long *)arg); + ret_val = get_default_threshold(info, argp); break; case CYSETDEFTHRESH: - ret_val = set_default_threshold(info, (unsigned long *)arg); + ret_val = set_default_threshold(info, argp); break; case CYGETTIMEOUT: - ret_val = get_timeout(info, (unsigned long *)arg); + ret_val = get_timeout(info, argp); break; case CYSETTIMEOUT: - ret_val = set_timeout(info, (unsigned long *)arg); + ret_val = set_timeout(info, argp); break; case CYGETDEFTIMEOUT: - ret_val = get_default_timeout(info, (unsigned long *)arg); + ret_val = get_default_timeout(info, argp); break; case CYSETDEFTIMEOUT: ret_val = set_default_timeout(info, (unsigned long)arg); @@ -1664,21 +1665,20 @@ cy_ioctl(struct tty_struct *tty, struct file * file, /* The following commands are incompletely implemented!!! */ case TIOCGSOFTCAR: - ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp); break; case TIOCSSOFTCAR: - ret_val = get_user(val, (unsigned long *) arg); + ret_val = get_user(val, (unsigned long __user *) argp); if (ret_val) break; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); break; case TIOCGSERIAL: - ret_val = get_serial_info(info, (struct serial_struct *) arg); + ret_val = get_serial_info(info, argp); break; case TIOCSSERIAL: - ret_val = set_serial_info(info, - (struct serial_struct *) arg); + ret_val = set_serial_info(info, argp); break; default: ret_val = -ENOIOCTLCMD; @@ -1773,7 +1773,7 @@ cy_close(struct tty_struct * tty, struct file * filp) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); info->event = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); @@ -2250,7 +2250,7 @@ scrn[1] = '\0'; info->card = index; info->line = port_num; info->flags = STD_COM_FLAGS; - info->tty = 0; + info->tty = NULL; info->xmit_fifo_size = 12; info->cor1 = CyPARITY_NONE|Cy_8_BITS; info->cor2 = CyETC; diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index d0b88d0e87f..7e1bd9562c2 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -183,11 +183,6 @@ static int sx_poll = HZ; static struct tty_driver *specialix_driver; -static unsigned long baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0, -}; - static struct specialix_board sx_board[SX_NBOARD] = { { 0, SX_IOBASE1, 9, }, { 0, SX_IOBASE2, 11, }, @@ -1090,9 +1085,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p if (baud == 38400) { if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baud ++; + baud = 57600; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baud += 2; + baud = 115200; } if (!baud) { @@ -1150,11 +1145,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p sx_out(bp, CD186x_RBPRL, tmp & 0xff); sx_out(bp, CD186x_TBPRL, tmp & 0xff); spin_unlock_irqrestore(&bp->lock, flags); - if (port->custom_divisor) { + if (port->custom_divisor) baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor; - baud = ( baud + 5 ) / 10; - } else - baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */ + baud = (baud + 5) / 10; /* Estimated CPS */ /* Two timer ticks seems enough to wakeup something like SLIP driver */ tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 5fec626598c..cc10af08cb0 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2602,7 +2602,7 @@ static void __exit sx_exit (void) } } if (misc_deregister(&sx_fw_device) < 0) { - printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n"); + printk (KERN_INFO "sx: couldn't deregister firmware loader device\n"); } sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized); if (sx_initialized) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index f2864cc6424..06784adcc35 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -133,8 +133,8 @@ static MGSL_PARAMS default_params = { }; #define SHARED_MEM_ADDRESS_SIZE 0x40000 -#define BUFFERLISTSIZE (PAGE_SIZE) -#define DMABUFFERSIZE (PAGE_SIZE) +#define BUFFERLISTSIZE 4096 +#define DMABUFFERSIZE 4096 #define MAXRXFRAMES 7 typedef struct _DMABUFFERENTRY diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index a082a2e3425..6ad2d3bb945 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1153,7 +1153,14 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend spin_unlock(&driver_lock); - sysfs_create_group(&dev->kobj, chip->vendor.attr_group); + if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { + list_del(&chip->list); + put_device(dev); + clear_bit(chip->dev_num, dev_mask); + kfree(chip); + kfree(devname); + return NULL; + } chip->bios_dir = tpm_bios_log_setup(devname); diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index ad8ffe49256..1ab0896070b 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -184,7 +184,9 @@ static int __init init_atmel(void) unsigned long base; struct tpm_chip *chip; - driver_register(&atml_drv); + rc = driver_register(&atml_drv); + if (rc) + return rc; if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { rc = -ENODEV; @@ -195,10 +197,8 @@ static int __init init_atmel(void) (atmel_request_region (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; - - if (IS_ERR - (pdev = - platform_device_register_simple("tpm_atmel", -1, NULL, 0))) { + pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0); + if (IS_ERR(pdev)) { rc = PTR_ERR(pdev); goto err_rel_reg; } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 26287aace87..608f73071be 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -284,7 +284,7 @@ static struct device_driver nsc_drv = { static int __init init_nsc(void) { int rc = 0; - int lo, hi; + int lo, hi, err; int nscAddrBase = TPM_ADDR; struct tpm_chip *chip; unsigned long base; @@ -297,7 +297,9 @@ static int __init init_nsc(void) return -ENODEV; } - driver_register(&nsc_drv); + err = driver_register(&nsc_drv); + if (err) + return err; hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 89e46d6dfc4..0187b118532 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -13,7 +13,7 @@ config WATCHDOG subsequently opening the file and then failing to write to it for longer than 1 minute will result in rebooting the machine. This could be useful for a networked machine that needs to come back - online as fast as possible after a lock-up. There's both a watchdog + on-line as fast as possible after a lock-up. There's both a watchdog implementation entirely in software (which can sometimes fail to reboot the machine) and a driver for hardware watchdog boards, which are more robust and can also keep track of the temperature inside @@ -60,7 +60,7 @@ config SOFT_WATCHDOG # ARM Architecture -config AT91_WATCHDOG +config AT91RM9200_WATCHDOG tristate "AT91RM9200 watchdog" depends on WATCHDOG && ARCH_AT91RM9200 help @@ -71,7 +71,7 @@ config 21285_WATCHDOG tristate "DC21285 watchdog" depends on WATCHDOG && FOOTBRIDGE help - The Intel Footbridge chip contains a builtin watchdog circuit. Say Y + The Intel Footbridge chip contains a built-in watchdog circuit. Say Y here if you wish to use this. Alternatively say M to compile the driver as a module, which will be called wdt285. @@ -269,11 +269,11 @@ config IB700_WDT Most people will say N. config IBMASR - tristate "IBM Automatic Server Restart" - depends on WATCHDOG && X86 - help + tristate "IBM Automatic Server Restart" + depends on WATCHDOG && X86 + help This is the driver for the IBM Automatic Server Restart watchdog - timer builtin into some eServer xSeries machines. + timer built-in into some eServer xSeries machines. To compile this driver as a module, choose M here: the module will be called ibmasr. @@ -316,13 +316,16 @@ config I8XX_TCO To compile this driver as a module, choose M here: the module will be called i8xx_tco. + Note: This driver will be removed in the near future. Please + use the Intel TCO Timer/Watchdog driver. + config ITCO_WDT - tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)" - depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL + tristate "Intel TCO Timer/Watchdog" + depends on WATCHDOG && (X86 || IA64) && PCI ---help--- Hardware driver for the intel TCO timer based watchdog devices. These drivers are included in the Intel 82801 I/O Controller - Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB + Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB controller hub. The TCO (Total Cost of Ownership) timer is a watchdog timer @@ -395,6 +398,26 @@ config CPU5_WDT To compile this driver as a module, choose M here: the module will be called cpu5wdt. +config SMSC37B787_WDT + tristate "Winbond SMsC37B787 Watchdog Timer" + depends on WATCHDOG && X86 + ---help--- + This is the driver for the hardware watchdog component on the + Winbond SMsC37B787 chipset as used on the NetRunner Mainboard + from Vision Systems and maybe others. + + This watchdog simply watches your kernel to make sure it doesn't + freeze, and if it does, it reboots your computer after a certain + amount of time. + + Usually a userspace daemon will notify the kernel WDT driver that + userspace is still alive, at regular intervals. + + To compile this driver as a module, choose M here: the + module will be called smsc37b787_wdt. + + Most people will say N. + config W83627HF_WDT tristate "W83627HF Watchdog Timer" depends on WATCHDOG && X86 @@ -410,6 +433,21 @@ config W83627HF_WDT Most people will say N. +config W83697HF_WDT + tristate "W83697HF/W83697HG Watchdog Timer" + depends on WATCHDOG && X86 + ---help--- + This is the driver for the hardware watchdog on the W83697HF/HG + chipset as used in Dedibox/VIA motherboards (and likely others). + This watchdog simply watches your kernel to make sure it doesn't + freeze, and if it does, it reboots your computer after a certain + amount of time. + + To compile this driver as a module, choose M here: the + module will be called w83697hf_wdt. + + Most people will say N. + config W83877F_WDT tristate "W83877F (EMACS) Watchdog Timer" depends on WATCHDOG && X86 @@ -443,7 +481,7 @@ config MACHZ_WDT depends on WATCHDOG && X86 ---help--- If you are using a ZF Micro MachZ processor, say Y here, otherwise - N. This is the driver for the watchdog timer builtin on that + N. This is the driver for the watchdog timer built-in on that processor using ZF-Logic interface. This watchdog simply watches your kernel to make sure it doesn't freeze, and if it does, it reboots your computer after a certain amount of time. @@ -472,7 +510,6 @@ config SBC_EPX_C3_WATCHDOG To compile this driver as a module, choose M here: the module will be called sbc_epx_c3. - # PowerPC Architecture config 8xx_WDT @@ -502,7 +539,7 @@ config WATCHDOG_RTAS help This driver adds watchdog support for the RTAS watchdog. - To compile this driver as a module, choose M here. The module + To compile this driver as a module, choose M here. The module will be called wdrtas. # MIPS Architecture @@ -556,7 +593,7 @@ config SH_WDT_MMAP help If you say Y here, user applications will be able to mmap the WDT/CPG registers. -# + # SPARC64 Architecture config WATCHDOG_CP1XXX diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 7f70abad465..36440497047 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o # ARM Architecture -obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o +obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o @@ -53,7 +53,9 @@ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_SBC8360_WDT) += sbc8360.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o +obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o +obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c index 5948863b592..bf25d0a55a9 100644 --- a/drivers/char/watchdog/alim7101_wdt.c +++ b/drivers/char/watchdog/alim7101_wdt.c @@ -77,7 +77,8 @@ static struct pci_dev *alim7101_pmu; static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")"); /* * Whack the dog @@ -415,6 +416,16 @@ err_out: module_init(alim7101_wdt_init); module_exit(alim7101_wdt_unload); +static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl); + MODULE_AUTHOR("Steve Hill"); MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c index 4e7a1145e78..4e7a1145e78 100644 --- a/drivers/char/watchdog/at91_wdt.c +++ b/drivers/char/watchdog/at91rm9200_wdt.c diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index aaac94db0d8..b6f29cb8bd3 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c @@ -35,6 +35,10 @@ * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, + * 82801HB (ICH8) : document number 313056-002, 313057-004, + * 82801HR (ICH8R) : document number 313056-002, 313057-004, + * 82801HH (ICH8DH) : document number 313056-002, 313057-004, + * 82801HO (ICH8DO) : document number 313056-002, 313057-004, * 6300ESB (6300ESB) : document number 300641-003 */ @@ -45,7 +49,7 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" #define DRV_VERSION "1.00" -#define DRV_RELDATE "30-Jul-2006" +#define DRV_RELDATE "08-Oct-2006" #define PFX DRV_NAME ": " /* Includes */ @@ -85,6 +89,9 @@ enum iTCO_chipsets { TCO_ICH7, /* ICH7 & ICH7R */ TCO_ICH7M, /* ICH7-M */ TCO_ICH7MDH, /* ICH7-M DH */ + TCO_ICH8, /* ICH8 & ICH8R */ + TCO_ICH8DH, /* ICH8DH */ + TCO_ICH8DO, /* ICH8DO */ }; static struct { @@ -108,6 +115,9 @@ static struct { {"ICH7 or ICH7R", 2}, {"ICH7-M", 2}, {"ICH7-M DH", 2}, + {"ICH8 or ICH8R", 2}, + {"ICH8DH", 2}, + {"ICH8DO", 2}, {NULL,0} }; @@ -135,6 +145,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); @@ -355,7 +368,8 @@ static int iTCO_wdt_get_timeleft (int *time_left) spin_unlock(&iTCO_wdt_private.io_lock); *time_left = (val8 * 6) / 10; - } + } else + return -EINVAL; return 0; } @@ -426,7 +440,6 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, { int new_options, retval = -EINVAL; int new_heartbeat; - int time_left; void __user *argp = (void __user *)arg; int __user *p = argp; static struct watchdog_info ident = { @@ -486,6 +499,8 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, case WDIOC_GETTIMELEFT: { + int time_left; + if (iTCO_wdt_get_timeleft(&time_left)) return -EINVAL; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 68b1ca976d5..18cb050c386 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -380,18 +380,21 @@ static int s3c2410wdt_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { printk(KERN_INFO PFX "failed to get irq resource\n"); + iounmap(wdt_base); return -ENOENT; } ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); if (ret != 0) { printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); + iounmap(wdt_base); return ret; } wdt_clock = clk_get(&pdev->dev, "watchdog"); if (wdt_clock == NULL) { printk(KERN_INFO PFX "failed to find watchdog clock source\n"); + iounmap(wdt_base); return -ENOENT; } @@ -415,6 +418,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) if (ret) { printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", WATCHDOG_MINOR, ret); + iounmap(wdt_base); return ret; } @@ -451,6 +455,7 @@ static int s3c2410wdt_remove(struct platform_device *dev) wdt_clock = NULL; } + iounmap(wdt_base); misc_deregister(&s3c2410wdt_miscdev); return 0; } diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index d8d0f28e0ac..e3239833e4b 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -392,7 +392,7 @@ static int __init sc1200wdt_init(void) if (io == -1) { printk(KERN_ERR PFX "io parameter must be specified\n"); ret = -EINVAL; - goto out_clean; + goto out_pnp; } #if defined CONFIG_PNP @@ -405,7 +405,7 @@ static int __init sc1200wdt_init(void) if (!request_region(io, io_len, SC1200_MODULE_NAME)) { printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); ret = -EBUSY; - goto out_clean; + goto out_pnp; } ret = sc1200wdt_probe(); @@ -435,6 +435,11 @@ out_rbt: out_io: release_region(io, io_len); +out_pnp: +#if defined CONFIG_PNP + if (isapnp) + pnp_unregister_driver(&scl200wdt_pnp_driver); +#endif goto out_clean; } diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c new file mode 100644 index 00000000000..9f56913b484 --- /dev/null +++ b/drivers/char/watchdog/smsc37b787_wdt.c @@ -0,0 +1,627 @@ +/* + * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x + * + * Based on acquirewdt.c by Alan Cox <alan@redhat.com> + * and some other existing drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The authors do NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (C) Copyright 2003-2006 Sven Anders <anders@anduras.de> + * + * History: + * 2003 - Created version 1.0 for Linux 2.4.x. + * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE + * features. Released version 1.1 + * + * Theory of operation: + * + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /dev/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * Create device with: + * mknod /dev/watchdog c 10 130 + * + * For an example userspace keep-alive daemon, see: + * Documentation/watchdog/watchdog.txt + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/ioport.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> + +/* enable support for minutes as units? */ +/* (does not always work correctly, so disabled by default!) */ +#define SMSC_SUPPORT_MINUTES +#undef SMSC_SUPPORT_MINUTES + +#define MAX_TIMEOUT 255 + +#define UNIT_SECOND 0 +#define UNIT_MINUTE 1 + +#define MODNAME "smsc37b787_wdt: " +#define VERSION "1.1" + +#define IOPORT 0x3F0 +#define IOPORT_SIZE 2 +#define IODEV_NO 8 + +static int unit = UNIT_SECOND; /* timer's unit */ +static int timeout = 60; /* timeout value: default is 60 "units" */ +static unsigned long timer_enabled = 0; /* is the timer enabled? */ + +static char expect_close; /* is the close expected? */ + +static spinlock_t io_lock; /* to guard the watchdog from io races */ + +static int nowayout = WATCHDOG_NOWAYOUT; + +/* -- Low level function ----------------------------------------*/ + +/* unlock the IO chip */ + +static inline void open_io_config(void) +{ + outb(0x55, IOPORT); + mdelay(1); + outb(0x55, IOPORT); +} + +/* lock the IO chip */ +static inline void close_io_config(void) +{ + outb(0xAA, IOPORT); +} + +/* select the IO device */ +static inline void select_io_device(unsigned char devno) +{ + outb(0x07, IOPORT); + outb(devno, IOPORT+1); +} + +/* write to the control register */ +static inline void write_io_cr(unsigned char reg, unsigned char data) +{ + outb(reg, IOPORT); + outb(data, IOPORT+1); +} + +/* read from the control register */ +static inline char read_io_cr(unsigned char reg) +{ + outb(reg, IOPORT); + return inb(IOPORT+1); +} + +/* -- Medium level functions ------------------------------------*/ + +static inline void gpio_bit12(unsigned char reg) +{ + // -- General Purpose I/O Bit 1.2 -- + // Bit 0, In/Out: 0 = Output, 1 = Input + // Bit 1, Polarity: 0 = No Invert, 1 = Invert + // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable + // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, + // 11 = Either Edge Triggered Intr. 2 + // Bit 5/6 (Reserved) + // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain + write_io_cr(0xE2, reg); +} + +static inline void gpio_bit13(unsigned char reg) +{ + // -- General Purpose I/O Bit 1.3 -- + // Bit 0, In/Out: 0 = Output, 1 = Input + // Bit 1, Polarity: 0 = No Invert, 1 = Invert + // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable + // Bit 3, Function select: 0 = GPI/O, 1 = LED + // Bit 4-6 (Reserved) + // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain + write_io_cr(0xE3, reg); +} + +static inline void wdt_timer_units(unsigned char new_units) +{ + // -- Watchdog timer units -- + // Bit 0-6 (Reserved) + // Bit 7, WDT Time-out Value Units Select + // (0 = Minutes, 1 = Seconds) + write_io_cr(0xF1, new_units); +} + +static inline void wdt_timeout_value(unsigned char new_timeout) +{ + // -- Watchdog Timer Time-out Value -- + // Bit 0-7 Binary coded units (0=Disabled, 1..255) + write_io_cr(0xF2, new_timeout); +} + +static inline void wdt_timer_conf(unsigned char conf) +{ + // -- Watchdog timer configuration -- + // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O + // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. + // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr. + // Bit 3 Reset the timer + // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled) + // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, + // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) + write_io_cr(0xF3, conf); +} + +static inline void wdt_timer_ctrl(unsigned char reg) +{ + // -- Watchdog timer control -- + // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured + // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz + // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) + // Bit 3 P20 Force Timeout enabled: + // 0 = P20 activity does not generate the WD timeout event + // 1 = P20 Allows rising edge of P20, from the keyboard + // controller, to force the WD timeout event. + // Bit 4 (Reserved) + // -- Soft power management -- + // Bit 5 Stop Counter: 1 = Stop software power down counter + // set via register 0xB8, (self-cleaning) + // (Upon read: 0 = Counter running, 1 = Counter stopped) + // Bit 6 Restart Counter: 1 = Restart software power down counter + // set via register 0xB8, (self-cleaning) + // Bit 7 SPOFF: 1 = Force software power down (self-cleaning) + + write_io_cr(0xF4, reg); +} + +/* -- Higher level functions ------------------------------------*/ + +/* initialize watchdog */ + +static void wb_smsc_wdt_initialize(void) +{ + unsigned char old; + + spin_lock(&io_lock); + open_io_config(); + select_io_device(IODEV_NO); + + // enable the watchdog + gpio_bit13(0x08); // Select pin 80 = LED not GPIO + gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert + + // disable the timeout + wdt_timeout_value(0); + + // reset control register + wdt_timer_ctrl(0x00); + + // reset configuration register + wdt_timer_conf(0x00); + + // read old (timer units) register + old = read_io_cr(0xF1) & 0x7F; + if (unit == UNIT_SECOND) old |= 0x80; // set to seconds + + // set the watchdog timer units + wdt_timer_units(old); + + close_io_config(); + spin_unlock(&io_lock); +} + +/* shutdown the watchdog */ + +static void wb_smsc_wdt_shutdown(void) +{ + spin_lock(&io_lock); + open_io_config(); + select_io_device(IODEV_NO); + + // disable the watchdog + gpio_bit13(0x09); + gpio_bit12(0x09); + + // reset watchdog config register + wdt_timer_conf(0x00); + + // reset watchdog control register + wdt_timer_ctrl(0x00); + + // disable timeout + wdt_timeout_value(0x00); + + close_io_config(); + spin_unlock(&io_lock); +} + +/* set timeout => enable watchdog */ + +static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) +{ + spin_lock(&io_lock); + open_io_config(); + select_io_device(IODEV_NO); + + // set Power LED to blink, if we enable the timeout + wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); + + // set timeout value + wdt_timeout_value(new_timeout); + + close_io_config(); + spin_unlock(&io_lock); +} + +/* get timeout */ + +static unsigned char wb_smsc_wdt_get_timeout(void) +{ + unsigned char set_timeout; + + spin_lock(&io_lock); + open_io_config(); + select_io_device(IODEV_NO); + set_timeout = read_io_cr(0xF2); + close_io_config(); + spin_unlock(&io_lock); + + return set_timeout; +} + +/* disable watchdog */ + +static void wb_smsc_wdt_disable(void) +{ + // set the timeout to 0 to disable the watchdog + wb_smsc_wdt_set_timeout(0); +} + +/* enable watchdog by setting the current timeout */ + +static void wb_smsc_wdt_enable(void) +{ + // set the current timeout... + wb_smsc_wdt_set_timeout(timeout); +} + +/* reset the timer */ + +static void wb_smsc_wdt_reset_timer(void) +{ + spin_lock(&io_lock); + open_io_config(); + select_io_device(IODEV_NO); + + // reset the timer + wdt_timeout_value(timeout); + wdt_timer_conf(0x08); + + close_io_config(); + spin_unlock(&io_lock); +} + +/* return, if the watchdog is enabled (timeout is set...) */ + +static int wb_smsc_wdt_status(void) +{ + return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING; +} + + +/* -- File operations -------------------------------------------*/ + +/* open => enable watchdog and set initial timeout */ + +static int wb_smsc_wdt_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + + if (test_and_set_bit(0, &timer_enabled)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + /* Reload and activate timer */ + wb_smsc_wdt_enable(); + + printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); + + return nonseekable_open(inode, file); +} + +/* close => shut off the timer */ + +static int wb_smsc_wdt_release(struct inode *inode, struct file *file) +{ + /* Shut off the timer. */ + + if (expect_close == 42) { + wb_smsc_wdt_disable(); + printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n"); + } else { + printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n"); + wb_smsc_wdt_reset_timer(); + } + + clear_bit(0, &timer_enabled); + expect_close = 0; + return 0; +} + +/* write => update the timer to keep the machine alive */ + +static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* reset expect flag */ + expect_close = 0; + + /* scan to see whether or not we got the magic character */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + wb_smsc_wdt_reset_timer(); + } + return len; +} + +/* ioctl => control interface */ + +static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int new_timeout; + + union { + struct watchdog_info __user *ident; + int __user *i; + } uarg; + + static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = "SMsC 37B787 Watchdog" + }; + + uarg.i = (int __user *)arg; + + switch (cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + return copy_to_user(uarg.ident, &ident, + sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + return put_user(wb_smsc_wdt_status(), uarg.i); + + case WDIOC_GETBOOTSTATUS: + return put_user(0, uarg.i); + + case WDIOC_KEEPALIVE: + wb_smsc_wdt_reset_timer(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, uarg.i)) + return -EFAULT; + + // the API states this is given in secs + if (unit == UNIT_MINUTE) + new_timeout /= 60; + + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; + + timeout = new_timeout; + wb_smsc_wdt_set_timeout(timeout); + + // fall through and return the new timeout... + + case WDIOC_GETTIMEOUT: + + new_timeout = timeout; + + if (unit == UNIT_MINUTE) + new_timeout *= 60; + + return put_user(new_timeout, uarg.i); + + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, uarg.i)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + wb_smsc_wdt_disable(); + retval = 0; + } + + if (options & WDIOS_ENABLECARD) { + wb_smsc_wdt_enable(); + retval = 0; + } + + return retval; + } + } +} + +/* -- Notifier funtions -----------------------------------------*/ + +static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + { + // set timeout to 0, to avoid possible race-condition + timeout = 0; + wb_smsc_wdt_disable(); + } + return NOTIFY_DONE; +} + +/* -- Module's structures ---------------------------------------*/ + +static struct file_operations wb_smsc_wdt_fops = +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wb_smsc_wdt_write, + .ioctl = wb_smsc_wdt_ioctl, + .open = wb_smsc_wdt_open, + .release = wb_smsc_wdt_release, +}; + +static struct notifier_block wb_smsc_wdt_notifier = +{ + .notifier_call = wb_smsc_wdt_notify_sys, +}; + +static struct miscdevice wb_smsc_wdt_miscdev = +{ + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wb_smsc_wdt_fops, +}; + +/* -- Module init functions -------------------------------------*/ + +/* module's "constructor" */ + +static int __init wb_smsc_wdt_init(void) +{ + int ret; + + spin_lock_init(&io_lock); + + printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n"); + + if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { + printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT); + ret = -EBUSY; + goto out_pnp; + } + + // set new maximum, if it's too big + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + // init the watchdog timer + wb_smsc_wdt_initialize(); + + ret = register_reboot_notifier(&wb_smsc_wdt_notifier); + if (ret) { + printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret); + goto out_io; + } + + ret = misc_register(&wb_smsc_wdt_miscdev); + if (ret) { + printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); + goto out_rbt; + } + + // output info + printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); + printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout); + + // ret = 0 + +out_clean: + return ret; + +out_rbt: + unregister_reboot_notifier(&wb_smsc_wdt_notifier); + +out_io: + release_region(IOPORT, IOPORT_SIZE); + +out_pnp: + goto out_clean; +} + +/* module's "destructor" */ + +static void __exit wb_smsc_wdt_exit(void) +{ + /* Stop the timer before we leave */ + if (!nowayout) + { + wb_smsc_wdt_shutdown(); + printk(KERN_INFO MODNAME "Watchdog disabled.\n"); + } + + misc_deregister(&wb_smsc_wdt_miscdev); + unregister_reboot_notifier(&wb_smsc_wdt_notifier); + release_region(IOPORT, IOPORT_SIZE); + + printk("SMsC 37B787 watchdog component driver removed.\n"); +} + +module_init(wb_smsc_wdt_init); +module_exit(wb_smsc_wdt_exit); + +MODULE_AUTHOR("Sven Anders <anders@anduras.de>"); +MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")"); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +#ifdef SMSC_SUPPORT_MINUTES +module_param(unit, int, 0); +MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0"); +#endif + +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index b4adc527e68..07d4bff2722 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -33,6 +33,7 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -44,6 +45,7 @@ static unsigned long wdt_is_open; static char expect_close; +static spinlock_t io_lock; /* You must set this - there is no sane way to probe for this board. */ static int wdt_io = 0x2E; @@ -110,12 +112,16 @@ w83627hf_init(void) static void wdt_ctrl(int timeout) { + spin_lock(&io_lock); + w83627hf_select_wd_register(); outb_p(0xF6, WDT_EFER); /* Select CRF6 */ outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ w83627hf_unselect_wd_register(); + + spin_unlock(&io_lock); } static int @@ -303,6 +309,8 @@ wdt_init(void) { int ret; + spin_lock_init(&io_lock); + printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); if (wdt_set_heartbeat(timeout)) { diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c new file mode 100644 index 00000000000..7768b55487c --- /dev/null +++ b/drivers/char/watchdog/w83697hf_wdt.c @@ -0,0 +1,450 @@ +/* + * w83697hf/hg WDT driver + * + * (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net> + * (c) Copyright 2006 Marcus Junker <junker@anduras.de> + * + * Based on w83627hf_wdt.c which is based on advantechwdt.c + * which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com> + * + * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> + * + * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Marcus Junker nor ANDURAS AG admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/fs.h> +#include <linux/ioport.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> + +#define WATCHDOG_NAME "w83697hf/hg WDT" +#define PFX WATCHDOG_NAME ": " +#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ + +static unsigned long wdt_is_open; +static char expect_close; +static spinlock_t io_lock; + +/* You must set this - there is no sane way to probe for this board. */ +static int wdt_io = 0x2e; +module_param(wdt_io, int, 0); +MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); + +static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Kernel methods. + */ + +#define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */ +#define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ +#define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */ + +static inline void +w83697hf_unlock(void) +{ + outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ + outb_p(0x87, W83697HF_EFER); /* Again according to manual */ +} + +static inline void +w83697hf_lock(void) +{ + outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ +} + +/* + * The three functions w83697hf_get_reg(), w83697hf_set_reg() and + * w83697hf_write_timeout() must be called with the device unlocked. + */ + +static unsigned char +w83697hf_get_reg(unsigned char reg) +{ + outb_p(reg, W83697HF_EFIR); + return inb_p(W83697HF_EFDR); +} + +static void +w83697hf_set_reg(unsigned char reg, unsigned char data) +{ + outb_p(reg, W83697HF_EFIR); + outb_p(data, W83697HF_EFDR); +} + +static void +w83697hf_write_timeout(int timeout) +{ + w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */ +} + +static void +w83697hf_select_wdt(void) +{ + w83697hf_unlock(); + w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ +} + +static inline void +w83697hf_deselect_wdt(void) +{ + w83697hf_lock(); +} + +static void +w83697hf_init(void) +{ + unsigned char bbuf; + + w83697hf_select_wdt(); + + bbuf = w83697hf_get_reg(0x29); + bbuf &= ~0x60; + bbuf |= 0x20; + w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ + + bbuf = w83697hf_get_reg(0xF3); + bbuf &= ~0x04; + w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */ + + w83697hf_deselect_wdt(); +} + +static int +wdt_ping(void) +{ + spin_lock(&io_lock); + w83697hf_select_wdt(); + + w83697hf_write_timeout(timeout); + + w83697hf_deselect_wdt(); + spin_unlock(&io_lock); + return 0; +} + +static int +wdt_enable(void) +{ + spin_lock(&io_lock); + w83697hf_select_wdt(); + + w83697hf_write_timeout(timeout); + w83697hf_set_reg(0x30, 1); /* Enable timer */ + + w83697hf_deselect_wdt(); + spin_unlock(&io_lock); + return 0; +} + +static int +wdt_disable(void) +{ + spin_lock(&io_lock); + w83697hf_select_wdt(); + + w83697hf_set_reg(0x30, 0); /* Disable timer */ + w83697hf_write_timeout(0); + + w83697hf_deselect_wdt(); + spin_unlock(&io_lock); + return 0; +} + +static int +wdt_set_heartbeat(int t) +{ + if ((t < 1) || (t > 255)) + return -EINVAL; + + timeout = t; + return 0; +} + +static ssize_t +wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + if (count) { + if (!nowayout) { + size_t i; + + expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf+i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + wdt_ping(); + } + return count; +} + +static int +wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_timeout; + static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "W83697HF WDT", + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &ident, sizeof(ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_KEEPALIVE: + wdt_ping(); + break; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, p)) + return -EFAULT; + if (wdt_set_heartbeat(new_timeout)) + return -EINVAL; + wdt_ping(); + /* Fall */ + + case WDIOC_GETTIMEOUT: + return put_user(timeout, p); + + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, p)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + wdt_disable(); + retval = 0; + } + + if (options & WDIOS_ENABLECARD) { + wdt_enable(); + retval = 0; + } + + return retval; + } + + default: + return -ENOTTY; + } + return 0; +} + +static int +wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + /* + * Activate + */ + + wdt_enable(); + return nonseekable_open(inode, file); +} + +static int +wdt_close(struct inode *inode, struct file *file) +{ + if (expect_close == 42) { + wdt_disable(); + } else { + printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + wdt_ping(); + } + expect_close = 0; + clear_bit(0, &wdt_is_open); + return 0; +} + +/* + * Notifier for system down + */ + +static int +wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + wdt_disable(); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wdt_write, + .ioctl = wdt_ioctl, + .open = wdt_open, + .release = wdt_close, +}; + +static struct miscdevice wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdt_fops, +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier = { + .notifier_call = wdt_notify_sys, +}; + +static int +w83697hf_check_wdt(void) +{ + if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { + printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io); + return -EIO; + } + + printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io); + w83697hf_unlock(); + if (w83697hf_get_reg(0x20) == 0x60) { + printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io); + w83697hf_lock(); + return 0; + } + w83697hf_lock(); /* Reprotect in case it was a compatible device */ + + printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); + release_region(wdt_io, 2); + return -EIO; +} + +static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; + +static int __init +wdt_init(void) +{ + int ret, i, found = 0; + + spin_lock_init(&io_lock); + + printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); + + if (wdt_io == 0) { + /* we will autodetect the W83697HF/HG watchdog */ + for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) { + wdt_io = w83697hf_ioports[i]; + if (!w83697hf_check_wdt()) + found++; + } + } else { + if (!w83697hf_check_wdt()) + found++; + } + + if (!found) { + printk (KERN_ERR PFX "No W83697HF/HG could be found\n"); + ret = -EIO; + goto out; + } + + w83697hf_init(); + wdt_disable(); /* Disable watchdog until first use */ + + if (wdt_set_heartbeat(timeout)) { + wdt_set_heartbeat(WATCHDOG_TIMEOUT); + printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", + WATCHDOG_TIMEOUT); + } + + ret = register_reboot_notifier(&wdt_notifier); + if (ret != 0) { + printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + ret); + goto unreg_regions; + } + + ret = misc_register(&wdt_miscdev); + if (ret != 0) { + printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto unreg_reboot; + } + + printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); + +out: + return ret; +unreg_reboot: + unregister_reboot_notifier(&wdt_notifier); +unreg_regions: + release_region(wdt_io, 2); + goto out; +} + +static void __exit +wdt_exit(void) +{ + misc_deregister(&wdt_miscdev); + unregister_reboot_notifier(&wdt_notifier); + release_region(wdt_io, 2); +} + +module_init(wdt_init); +module_exit(wdt_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, Samuel Tardieu <sam@rfc1149.net>"); +MODULE_DESCRIPTION("w83697hf/hg WDT driver"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 7ad3be8c0f4..7fcb77a9d01 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -54,8 +54,8 @@ static cycle_t acpi_pm_read_verified(void) v1 = read_pmtmr(); v2 = read_pmtmr(); v3 = read_pmtmr(); - } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) - || (v3 > v1 && v3 < v2)); + } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) + || (v3 > v1 && v3 < v2))); return (cycle_t)v2; } @@ -138,6 +138,8 @@ static void __devinit acpi_pm_check_graylist(struct pci_dev *dev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, acpi_pm_check_graylist); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, + acpi_pm_check_graylist); #endif diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 2cc71b66231..491779af8d5 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -107,6 +107,7 @@ config CPU_FREQ_GOV_USERSPACE config CPU_FREQ_GOV_ONDEMAND tristate "'ondemand' cpufreq policy governor" + select CPU_FREQ_TABLE help 'ondemand' - This driver adds a dynamic cpufreq policy governor. The governor does a periodic polling and diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 86e69b7f912..dd0c2623e27 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -59,7 +59,7 @@ static int __init init_cpufreq_transition_notifier_list(void) srcu_init_notifier_head(&cpufreq_transition_notifier_list); return 0; } -core_initcall(init_cpufreq_transition_notifier_list); +pure_initcall(init_cpufreq_transition_notifier_list); static LIST_HEAD(cpufreq_governor_list); static DEFINE_MUTEX (cpufreq_governor_mutex); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 4bde30bb3be..75e9e38330f 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -230,34 +230,43 @@ static struct kobj_type ktype_memctrl = { */ static int edac_sysfs_memctrl_setup(void) { - int err=0; + int err = 0; debugf1("%s()\n", __func__); /* create the /sys/devices/system/edac directory */ err = sysdev_class_register(&edac_class); - if (!err) { - /* Init the MC's kobject */ - memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); - edac_memctrl_kobj.parent = &edac_class.kset.kobj; - edac_memctrl_kobj.ktype = &ktype_memctrl; + if (err) { + debugf1("%s() error=%d\n", __func__, err); + return err; + } - /* generate sysfs "..../edac/mc" */ - err = kobject_set_name(&edac_memctrl_kobj,"mc"); + /* Init the MC's kobject */ + memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); + edac_memctrl_kobj.parent = &edac_class.kset.kobj; + edac_memctrl_kobj.ktype = &ktype_memctrl; - if (!err) { - /* FIXME: maybe new sysdev_create_subdir() */ - err = kobject_register(&edac_memctrl_kobj); + /* generate sysfs "..../edac/mc" */ + err = kobject_set_name(&edac_memctrl_kobj,"mc"); - if (err) - debugf1("Failed to register '.../edac/mc'\n"); - else - debugf1("Registered '.../edac/mc' kobject\n"); - } - } else - debugf1("%s() error=%d\n", __func__, err); + if (err) + goto fail; + + /* FIXME: maybe new sysdev_create_subdir() */ + err = kobject_register(&edac_memctrl_kobj); + + if (err) { + debugf1("Failed to register '.../edac/mc'\n"); + goto fail; + } + debugf1("Registered '.../edac/mc' kobject\n"); + + return 0; + +fail: + sysdev_class_unregister(&edac_class); return err; } diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 3a365e159d8..d944647c82c 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -226,14 +226,26 @@ static int __init eisa_init_device (struct eisa_root_device *root, static int __init eisa_register_device (struct eisa_device *edev) { - if (device_register (&edev->dev)) - return -1; + int rc = device_register (&edev->dev); + if (rc) + return rc; - device_create_file (&edev->dev, &dev_attr_signature); - device_create_file (&edev->dev, &dev_attr_enabled); - device_create_file (&edev->dev, &dev_attr_modalias); + rc = device_create_file (&edev->dev, &dev_attr_signature); + if (rc) goto err_devreg; + rc = device_create_file (&edev->dev, &dev_attr_enabled); + if (rc) goto err_sig; + rc = device_create_file (&edev->dev, &dev_attr_modalias); + if (rc) goto err_enab; return 0; + +err_enab: + device_remove_file (&edev->dev, &dev_attr_enabled); +err_sig: + device_remove_file (&edev->dev, &dev_attr_signature); +err_devreg: + device_unregister(&edev->dev); + return rc; } static int __init eisa_request_resources (struct eisa_root_device *root, diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index 22d17474755..ca4e67a022d 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -70,9 +70,9 @@ #define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp)) #define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->device->host->hostdata[0])) -#define SC_FCMND(fcmnd) ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp))) +#define SC_FCMND(fcmnd) ((struct scsi_cmnd *)((long)fcmnd - (long)&(((struct scsi_cmnd *)0)->SCp))) -static int fcp_scsi_queue_it(fc_channel *, Scsi_Cmnd *, fcp_cmnd *, int); +static int fcp_scsi_queue_it(fc_channel *, struct scsi_cmnd *, fcp_cmnd *, int); void fcp_queue_empty(fc_channel *); static void fcp_scsi_insert_queue (fc_channel *fc, fcp_cmnd *fcmd) @@ -378,14 +378,14 @@ void fcp_register(fc_channel *fc, u8 type, int unregister) printk ("FC: %segistering unknown type %02x\n", unregister ? "Unr" : "R", type); } -static void fcp_scsi_done(Scsi_Cmnd *SCpnt); +static void fcp_scsi_done(struct scsi_cmnd *SCpnt); static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hdr *fch) { fcp_cmnd *fcmd; fcp_rsp *rsp; int host_status; - Scsi_Cmnd *SCpnt; + struct scsi_cmnd *SCpnt; int sense_len; int rsp_status; @@ -757,13 +757,14 @@ void fcp_release(fc_channel *fcchain, int count) /* count must > 0 */ } -static void fcp_scsi_done (Scsi_Cmnd *SCpnt) +static void fcp_scsi_done(struct scsi_cmnd *SCpnt) { if (FCP_CMND(SCpnt)->done) FCP_CMND(SCpnt)->done(SCpnt); } -static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare) +static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt, + fcp_cmnd *fcmd, int prepare) { long i; fcp_cmd *cmd; @@ -837,7 +838,8 @@ static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, i return 0; } -int fcp_scsi_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *)) +int fcp_scsi_queuecommand(struct scsi_cmnd *SCpnt, + void (* done)(struct scsi_cmnd *)) { fcp_cmnd *fcmd = FCP_CMND(SCpnt); fc_channel *fc = FC_SCMND(SCpnt); @@ -873,7 +875,7 @@ void fcp_queue_empty(fc_channel *fc) } } -int fcp_scsi_abort(Scsi_Cmnd *SCpnt) +int fcp_scsi_abort(struct scsi_cmnd *SCpnt) { /* Internal bookkeeping only. Lose 1 cmd_slots slot. */ fcp_cmnd *fcmd = FCP_CMND(SCpnt); @@ -910,7 +912,7 @@ int fcp_scsi_abort(Scsi_Cmnd *SCpnt) } #if 0 -void fcp_scsi_reset_done(Scsi_Cmnd *SCpnt) +void fcp_scsi_reset_done(struct scsi_cmnd *SCpnt) { fc_channel *fc = FC_SCMND(SCpnt); @@ -921,7 +923,7 @@ void fcp_scsi_reset_done(Scsi_Cmnd *SCpnt) #define FCP_RESET_TIMEOUT (2*HZ) -int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt) +int fcp_scsi_dev_reset(struct scsi_cmnd *SCpnt) { #if 0 /* broken junk, but if davem wants to compile this driver, let him.. */ unsigned long flags; @@ -931,7 +933,7 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt) DECLARE_MUTEX_LOCKED(sem); if (!fc->rst_pkt) { - fc->rst_pkt = (Scsi_Cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL); + fc->rst_pkt = (struct scsi_cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL); if (!fc->rst_pkt) return FAILED; fcmd = FCP_CMND(fc->rst_pkt); @@ -999,7 +1001,7 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt) return SUCCESS; } -static int __fcp_scsi_host_reset(Scsi_Cmnd *SCpnt) +static int __fcp_scsi_host_reset(struct scsi_cmnd *SCpnt) { fc_channel *fc = FC_SCMND(SCpnt); fcp_cmnd *fcmd = FCP_CMND(SCpnt); @@ -1020,7 +1022,7 @@ static int __fcp_scsi_host_reset(Scsi_Cmnd *SCpnt) else return FAILED; } -int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt) +int fcp_scsi_host_reset(struct scsi_cmnd *SCpnt) { unsigned long flags; int rc; diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h index c397c84bef6..1ac61330592 100644 --- a/drivers/fc4/fcp_impl.h +++ b/drivers/fc4/fcp_impl.h @@ -39,7 +39,7 @@ struct _fc_channel; typedef struct fcp_cmnd { struct fcp_cmnd *next; struct fcp_cmnd *prev; - void (*done)(Scsi_Cmnd *); + void (*done)(struct scsi_cmnd *); unsigned short proto; unsigned short token; unsigned int did; @@ -94,14 +94,14 @@ typedef struct _fc_channel { long *scsi_bitmap; long scsi_bitmap_end; int scsi_free; - int (*encode_addr)(Scsi_Cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *); + int (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *); fcp_cmnd *scsi_que; char scsi_name[4]; fcp_cmnd **cmd_slots; int channels; int targets; long *ages; - Scsi_Cmnd *rst_pkt; + struct scsi_cmnd *rst_pkt; fcp_posmap *posmap; /* LOGIN stuff */ fcp_cmnd *login; @@ -155,9 +155,10 @@ int fc_do_prli(fc_channel *, unsigned char); for_each_fc_channel(fc) \ if (fc->state == FC_STATE_ONLINE) -int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int fcp_scsi_abort(Scsi_Cmnd *); -int fcp_scsi_dev_reset(Scsi_Cmnd *); -int fcp_scsi_host_reset(Scsi_Cmnd *); +int fcp_scsi_queuecommand(struct scsi_cmnd *, + void (* done) (struct scsi_cmnd *)); +int fcp_scsi_abort(struct scsi_cmnd *); +int fcp_scsi_dev_reset(struct scsi_cmnd *); +int fcp_scsi_host_reset(struct scsi_cmnd *); #endif /* !(_FCP_SCSI_H) */ diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 8bcb58cd4ac..1865b56fb14 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -8,7 +8,7 @@ * * See Documentation/dcdbas.txt for more information. * - * Copyright (C) 1995-2005 Dell Inc. + * Copyright (C) 1995-2006 Dell Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License v2.0 as published by @@ -40,7 +40,7 @@ #include "dcdbas.h" #define DRIVER_NAME "dcdbas" -#define DRIVER_VERSION "5.6.0-2" +#define DRIVER_VERSION "5.6.0-3.2" #define DRIVER_DESCRIPTION "Dell Systems Management Base Driver" static struct platform_device *dcdbas_pdev; @@ -175,6 +175,9 @@ static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos, { ssize_t ret; + if ((pos + count) > MAX_SMI_DATA_BUF_SIZE) + return -EINVAL; + mutex_lock(&smi_data_lock); ret = smi_data_buf_realloc(pos + count); diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index fc17599c905..fc702e40bd4 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -249,7 +249,7 @@ static int packetize_data(void *data, size_t length) if ((rc = create_packet(temp, packet_length))) return rc; - pr_debug("%p:%lu\n", temp, (end - temp)); + pr_debug("%p:%td\n", temp, (end - temp)); temp += packet_length; } @@ -705,27 +705,39 @@ static struct bin_attribute rbu_packet_size_attr = { static int __init dcdrbu_init(void) { - int rc = 0; + int rc; spin_lock_init(&rbu_data.lock); init_packet_head(); - rbu_device = - platform_device_register_simple("dell_rbu", -1, NULL, 0); - if (!rbu_device) { + rbu_device = platform_device_register_simple("dell_rbu", -1, NULL, 0); + if (IS_ERR(rbu_device)) { printk(KERN_ERR "dell_rbu:%s:platform_device_register_simple " "failed\n", __FUNCTION__); - return -EIO; + return PTR_ERR(rbu_device); } - sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); - sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); - sysfs_create_bin_file(&rbu_device->dev.kobj, + rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); + if (rc) + goto out_devreg; + rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); + if (rc) + goto out_data; + rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_packet_size_attr); + if (rc) + goto out_imtype; rbu_data.entry_created = 0; - return rc; + return 0; +out_imtype: + sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); +out_data: + sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); +out_devreg: + platform_device_unregister(rbu_device); + return rc; } static __exit void dcdrbu_exit(void) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b8b596d5778..37deee6c0c1 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -326,6 +326,26 @@ char *dmi_get_system_info(int field) } EXPORT_SYMBOL(dmi_get_system_info); + +/** + * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. + * @str: Case sensitive Name + */ +int dmi_name_in_vendors(char *str) +{ + static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, + DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; + int i; + for (i = 0; fields[i] != DMI_NONE; i++) { + int f = fields[i]; + if (dmi_ident[f] && strstr(dmi_ident[f], str)) + return 1; + } + return 0; +} +EXPORT_SYMBOL(dmi_name_in_vendors); + /** * dmi_find_device - find onboard device by type/name * @type: device type or %DMI_DEV_TYPE_ANY to match all device types diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 8ebce1c03ad..5ab5e393b88 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -639,7 +639,12 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, kobject_set_name(&new_efivar->kobj, "%s", short_name); kobj_set_kset_s(new_efivar, vars_subsys); - kobject_register(&new_efivar->kobj); + i = kobject_register(&new_efivar->kobj); + if (i) { + kfree(short_name); + kfree(new_efivar); + return 1; + } kfree(short_name); short_name = NULL; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9b88b25b6ed..e76d91906c9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -95,11 +95,13 @@ config SENSORS_ADM9240 will be called adm9240. config SENSORS_K8TEMP - tristate "AMD K8 processor sensor" + tristate "AMD Athlon64/FX or Opteron temperature sensor" depends on HWMON && X86 && PCI && EXPERIMENTAL help If you say yes here you get support for the temperature - sensor(s) inside your AMD K8 CPU. + sensor(s) inside your CPU. Supported is whole AMD K8 + microarchitecture. Please note that you will need at least + lm-sensors 2.10.1 for proper userspace support. This driver can also be built as a module. If so, the module will be called k8temp. @@ -369,8 +371,8 @@ config SENSORS_SMSC47M1 help If you say yes here you get support for the integrated fan monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and - LPC47M997 chips. + LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x, + LPC47M192 and LPC47M997 chips. The temperature and voltage sensor features of the LPC47M192 and LPC47M997 are supported by another driver, select also diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 377961c4a41..aad594adf0c 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -5,7 +5,7 @@ * Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl> * Philip Edelbrock <phil@netroedge.com> * Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl> - * Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable + * Copyright (C) 2005 Grant Coady <gcoady.lk@gmail.com> with valuable * guidance from Jean Delvare * * Driver supports Analog Devices ADM9240 @@ -774,7 +774,7 @@ static void __exit sensors_adm9240_exit(void) } MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, " - "Grant Coady <gcoady@gmail.com> and others"); + "Grant Coady <gcoady.lk@gmail.com> and others"); MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index ac1b746df6d..73bc2ffc598 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -815,18 +815,18 @@ static int __init sm_lm78_init(void) if (res) return res; - res = i2c_isa_add_driver(&lm78_isa_driver); - if (res) { - i2c_del_driver(&lm78_driver); - return res; - } + /* Don't exit if this one fails, we still want the I2C variants + to work! */ + if (i2c_isa_add_driver(&lm78_isa_driver)) + isa_address = 0; return 0; } static void __exit sm_lm78_exit(void) { - i2c_isa_del_driver(&lm78_isa_driver); + if (isa_address) + i2c_isa_del_driver(&lm78_isa_driver); i2c_del_driver(&lm78_driver); } diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 47132fd26b1..beb881c4b2e 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -2,8 +2,8 @@ smsc47m1.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, - LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, + LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> @@ -380,8 +380,8 @@ static int __init smsc47m1_find(unsigned short *addr) val = superio_inb(SUPERIO_REG_DEVID); /* - * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id - * 0x5F) and LPC47B27x (device id 0x51) have fan control. + * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x + * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" * can do much more besides (device id 0x60). * The LPC47M997 is undocumented, but seems to be compatible with @@ -390,7 +390,8 @@ static int __init smsc47m1_find(unsigned short *addr) if (val == 0x51) printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC " + "LPC47M10x/LPC47M112/LPC47M13x\n"); else if (val == 0x5F) printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); else if (val == 0x60) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 833faa275ff..2257806d010 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -354,6 +354,8 @@ static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) case 0: reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) | ((data->fan_div[0] & 0x03) << 4); + /* fan5 input control bit is write only, compute the value */ + reg |= (data->has_fan & (1 << 4)) ? 1 : 0; w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) | ((data->fan_div[0] & 0x04) << 3); @@ -362,6 +364,8 @@ static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) case 1: reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) | ((data->fan_div[1] & 0x03) << 6); + /* fan5 input control bit is write only, compute the value */ + reg |= (data->has_fan & (1 << 4)) ? 1 : 0; w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) | ((data->fan_div[1] & 0x04) << 4); @@ -1216,13 +1220,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) superio_exit(); /* It looks like fan4 and fan5 pins can be alternatively used - as fan on/off switches */ + as fan on/off switches, but fan5 control is write only :/ + We assume that if the serial interface is disabled, designers + connected fan5 as input unless they are emitting log 1, which + is not the default. */ data->has_fan = 0x07; /* fan1, fan2 and fan3 */ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); if ((i & (1 << 2)) && (!fan4pin)) data->has_fan |= (1 << 3); - if ((i & (1 << 0)) && (!fan5pin)) + if (!(i & (1 << 1)) && (!fan5pin)) data->has_fan |= (1 << 4); /* Register sysfs hooks */ diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index a4584ec6984..1232171c3aa 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1099,7 +1099,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) bank. */ if (kind < 0) { if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) { - dev_dbg(dev, "Detection failed at step 3\n"); + dev_dbg(&adapter->dev, "Detection of w83781d chip " + "failed at step 3\n"); err = -ENODEV; goto ERROR2; } @@ -1109,7 +1110,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if ((!(val1 & 0x07)) && (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { - dev_dbg(dev, "Detection failed at step 4\n"); + dev_dbg(&adapter->dev, "Detection of w83781d chip " + "failed at step 4\n"); err = -ENODEV; goto ERROR2; } @@ -1119,7 +1121,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) ((val1 & 0x80) && (val2 == 0x5c)))) { if (w83781d_read_value (client, W83781D_REG_I2C_ADDR) != address) { - dev_dbg(dev, "Detection failed at step 5\n"); + dev_dbg(&adapter->dev, "Detection of w83781d " + "chip failed at step 5\n"); err = -ENODEV; goto ERROR2; } @@ -1141,8 +1144,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) else if (val2 == 0x12) vendid = asus; else { - dev_dbg(dev, "Chip was made by neither " - "Winbond nor Asus?\n"); + dev_dbg(&adapter->dev, "w83781d chip vendor is " + "neither Winbond nor Asus\n"); err = -ENODEV; goto ERROR2; } @@ -1161,10 +1164,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind = as99127f; else { if (kind == 0) - dev_warn(dev, "Ignoring 'force' " + dev_warn(&adapter->dev, "Ignoring 'force' " "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); + "address 0x%02x\n", address); err = -EINVAL; goto ERROR2; } @@ -1685,11 +1687,10 @@ sensors_w83781d_init(void) if (res) return res; - res = i2c_isa_add_driver(&w83781d_isa_driver); - if (res) { - i2c_del_driver(&w83781d_driver); - return res; - } + /* Don't exit if this one fails, we still want the I2C variants + to work! */ + if (i2c_isa_add_driver(&w83781d_isa_driver)) + isa_address = 0; return 0; } @@ -1697,7 +1698,8 @@ sensors_w83781d_init(void) static void __exit sensors_w83781d_exit(void) { - i2c_isa_del_driver(&w83781d_isa_driver); + if (isa_address) + i2c_isa_del_driver(&w83781d_isa_driver); i2c_del_driver(&w83781d_driver); } diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 371ed4f69a9..9e5f885368b 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -746,6 +746,52 @@ static ssize_t store_vrm_reg(struct device *dev, static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define IN_UNIT_ATTRS(X) \ + &sda_in_input[X].dev_attr.attr, \ + &sda_in_min[X].dev_attr.attr, \ + &sda_in_max[X].dev_attr.attr + +#define FAN_UNIT_ATTRS(X) \ + &sda_fan_input[X].dev_attr.attr, \ + &sda_fan_min[X].dev_attr.attr, \ + &sda_fan_div[X].dev_attr.attr + +#define TEMP_UNIT_ATTRS(X) \ + &sda_temp_input[X].dev_attr.attr, \ + &sda_temp_max[X].dev_attr.attr, \ + &sda_temp_max_hyst[X].dev_attr.attr + +static struct attribute *w83791d_attributes[] = { + IN_UNIT_ATTRS(0), + IN_UNIT_ATTRS(1), + IN_UNIT_ATTRS(2), + IN_UNIT_ATTRS(3), + IN_UNIT_ATTRS(4), + IN_UNIT_ATTRS(5), + IN_UNIT_ATTRS(6), + IN_UNIT_ATTRS(7), + IN_UNIT_ATTRS(8), + IN_UNIT_ATTRS(9), + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + FAN_UNIT_ATTRS(3), + FAN_UNIT_ATTRS(4), + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), + &dev_attr_alarms.attr, + &sda_beep_ctrl[0].dev_attr.attr, + &sda_beep_ctrl[1].dev_attr.attr, + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + NULL +}; + +static const struct attribute_group w83791d_group = { + .attrs = w83791d_attributes, +}; + /* This function is called when: * w83791d_driver is inserted (when this module is loaded), for each available adapter @@ -967,41 +1013,20 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind) } /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group))) + goto error3; + + /* Everything is ready, now register the working device */ data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto error3; + goto error4; } - for (i = 0; i < NUMBER_OF_VIN; i++) { - device_create_file(dev, &sda_in_input[i].dev_attr); - device_create_file(dev, &sda_in_min[i].dev_attr); - device_create_file(dev, &sda_in_max[i].dev_attr); - } - - for (i = 0; i < NUMBER_OF_FANIN; i++) { - device_create_file(dev, &sda_fan_input[i].dev_attr); - device_create_file(dev, &sda_fan_div[i].dev_attr); - device_create_file(dev, &sda_fan_min[i].dev_attr); - } - - for (i = 0; i < NUMBER_OF_TEMPIN; i++) { - device_create_file(dev, &sda_temp_input[i].dev_attr); - device_create_file(dev, &sda_temp_max[i].dev_attr); - device_create_file(dev, &sda_temp_max_hyst[i].dev_attr); - } - - device_create_file(dev, &dev_attr_alarms); - - for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) { - device_create_file(dev, &sda_beep_ctrl[i].dev_attr); - } - - device_create_file(dev, &dev_attr_cpu0_vid); - device_create_file(dev, &dev_attr_vrm); - return 0; +error4: + sysfs_remove_group(&client->dev.kobj, &w83791d_group); error3: if (data->lm75[0] != NULL) { i2c_detach_client(data->lm75[0]); @@ -1025,8 +1050,10 @@ static int w83791d_detach_client(struct i2c_client *client) int err; /* main client */ - if (data) + if (data) { hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &w83791d_group); + } if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 4380653748a..8ed59a2dff5 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -91,7 +91,7 @@ int i2c_isa_add_driver(struct i2c_driver *driver) /* Now look for clients */ res = driver->attach_adapter(&isa_adapter); if (res) { - dev_err(&isa_adapter.dev, + dev_dbg(&isa_adapter.dev, "Driver %s failed to attach adapter, unregistering\n", driver->driver.name); driver_unregister(&driver->driver); diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 1ce01fb0ac0..05fffb9415a 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -137,7 +137,8 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev) gpio_line_set(gpio->scl_pin, 0); gpio_line_set(gpio->sda_pin, 0); - if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) { + err = i2c_bit_add_bus(&drv_data->adapter); + if (err != 0) printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id); kfree(drv_data); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 81050d3c9b2..c95a6c15416 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -272,7 +272,8 @@ static int i2c_pxa_wait_slave(struct pxa_i2c *i2c) dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", __func__, (long)jiffies, ISR, ICR, IBMR); - if ((ISR & (ISR_UB|ISR_IBB|ISR_SAD)) == ISR_SAD || + if ((ISR & (ISR_UB|ISR_IBB)) == 0 || + (ISR & ISR_SAD) != 0 || (ICR & ICR_SCLE) == 0) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); @@ -492,7 +493,10 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) if (isr & ISR_BED) { /* what should we do here? */ } else { - int ret = i2c->slave->read(i2c->slave->data); + int ret = 0; + + if (i2c->slave != NULL) + ret = i2c->slave->read(i2c->slave->data); IDBR = ret; ICR |= ICR_TB; /* allow next byte */ diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 32aab0d34ee..714bae78095 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -494,11 +494,12 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, iface->pdev = pdev; iface->bar = bar; - pci_enable_device_bars(iface->pdev, 1 << iface->bar); + rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar); + if (rc) + goto errout_free; rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name); - - if (rc != 0) { + if (rc) { printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n", iface->bar); goto errout_free; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 69bbb6206a0..88214943d00 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -597,7 +597,7 @@ static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq) struct cdrom_info *cd = drive->driver_data; ide_init_drive_cmd(rq); - rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_type = REQ_TYPE_ATA_PC; rq->rq_disk = cd->disk; } @@ -716,7 +716,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) ide_error(drive, "request sense failure", stat); return 1; - } else if (blk_pc_request(rq)) { + } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { /* All other functions, except for READ. */ unsigned long flags; @@ -724,7 +724,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) * if we have an error, pass back CHECK_CONDITION as the * scsi status byte */ - if (!rq->errors) + if (blk_pc_request(rq) && !rq->errors) rq->errors = SAM_STAT_CHECK_CONDITION; /* Check for tray open. */ @@ -2023,7 +2023,8 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) } info->last_block = block; return action; - } else if (rq->cmd_type == REQ_TYPE_SENSE) { + } else if (rq->cmd_type == REQ_TYPE_SENSE || + rq->cmd_type == REQ_TYPE_ATA_PC) { return cdrom_do_packet_command(drive); } else if (blk_pc_request(rq)) { return cdrom_do_block_pc(drive, rq); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 1d0470c1f95..30175c7688e 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -524,8 +524,8 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) task_ioreg_t *hobsptr = args.hobRegister; int err = 0; int tasksize = sizeof(struct ide_task_request_s); - int taskin = 0; - int taskout = 0; + unsigned int taskin = 0; + unsigned int taskout = 0; u8 io_32bit = drive->io_32bit; char __user *buf = (char __user *)arg; @@ -538,8 +538,13 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) return -EFAULT; } - taskout = (int) req_task->out_size; - taskin = (int) req_task->in_size; + taskout = req_task->out_size; + taskin = req_task->in_size; + + if (taskin > 65536 || taskout > 65536) { + err = -EINVAL; + goto abort; + } if (taskout) { int outtotal = tasksize; diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index b1d5291531b..45ed03591cd 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -459,7 +459,7 @@ ok_to_read: #ifdef DEBUG printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n", req->rq_disk->disk_name, req->sector, req->nr_sectors, - req->buffer+512)); + req->buffer+512); #endif if (req->current_nr_sectors <= 0) end_request(req, 1); diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 2b0ea8b6608..753fe0e2145 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -75,6 +75,7 @@ static struct amd_ide_chip { { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, { 0 } }; @@ -491,7 +492,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"), /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"), - /* 19 */ DECLARE_AMD_DEV("AMD5536"), + /* 19 */ DECLARE_NV_DEV("NFORCE-MCP67"), + /* 20 */ DECLARE_AMD_DEV("AMD5536"), }; static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -530,7 +532,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 965c43659e3..9f306880491 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -40,6 +40,19 @@ static int ide_generic_all; /* Set to claim all devices */ +/* + * the module_param_named() was added for the modular case + * the __setup() is left as compatibility for existing setups + */ +#ifndef MODULE +static int __init ide_generic_all_on(char *unused) +{ + ide_generic_all = 1; + printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n"); + return 1; +} +__setup("all-generic-ide", ide_generic_all_on); +#endif module_param_named(all_generic_ide, ide_generic_all, bool, 0444); MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers."); @@ -234,13 +247,17 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi (!(PCI_FUNC(dev->devfn) & 1))) goto out; - if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1) - goto out; + if (dev->vendor == PCI_VENDOR_ID_JMICRON) { + if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 && PCI_FUNC(dev->devfn) != 1) + goto out; + } - pci_read_config_word(dev, PCI_COMMAND, &command); - if (!(command & PCI_COMMAND_IO)) { - printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); - goto out; + if (dev->vendor != PCI_VENDOR_ID_JMICRON) { + pci_read_config_word(dev, PCI_COMMAND, &command); + if (!(command & PCI_COMMAND_IO)) { + printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); + goto out; + } } ret = ide_setup_pci_device(dev, d); out: diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index f3fe287fbd8..244f7eb7006 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -774,7 +774,7 @@ ioc4_ide_exit(void) ioc4_unregister_submodule(&ioc4_ide_submodule); } -module_init(ioc4_ide_init); +late_initcall(ioc4_ide_init); /* Call only after IDE init is done */ module_exit(ioc4_ide_exit); MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon"); diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 8a7b8fab623..31e5cc49d61 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -64,6 +64,7 @@ #include <linux/ethtool.h> #include <asm/uaccess.h> #include <asm/delay.h> +#include <asm/unaligned.h> #include <net/arp.h> #include "config_roms.h" @@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) int i; struct eth1394_priv *priv = netdev_priv(dev); struct hpsb_host *host = priv->host; - u64 guid = *((u64*)&(host->csr.rom->bus_info_data[3])); + u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3])); u16 maxpayload = 1 << (host->csr.max_rec + 1); int max_speed = IEEE1394_SPEED_MAX; @@ -514,8 +515,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) ETHER1394_GASP_OVERHEAD))); /* Set our hardware address while we're at it */ - *(u64*)dev->dev_addr = guid; - *(u64*)dev->broadcast = ~0x0ULL; + memcpy(dev->dev_addr, &guid, sizeof(u64)); + memset(dev->broadcast, 0xff, sizeof(u64)); } spin_unlock_irqrestore (&priv->lock, flags); @@ -894,6 +895,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, u16 maxpayload; struct eth1394_node_ref *node; struct eth1394_node_info *node_info; + __be64 guid; /* Sanity check. MacOSX seems to be sending us 131 in this * field (atleast on my Panther G5). Not sure why. */ @@ -902,8 +904,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1))); + guid = get_unaligned(&arp1394->s_uniq_id); node = eth1394_find_node_guid(&priv->ip_node_list, - be64_to_cpu(arp1394->s_uniq_id)); + be64_to_cpu(guid)); if (!node) { return 0; } @@ -931,10 +934,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, arp_ptr += arp->ar_pln; /* skip over sender IP addr */ if (arp->ar_op == htons(ARPOP_REQUEST)) - /* just set ARP req target unique ID to 0 */ - *((u64*)arp_ptr) = 0; + memset(arp_ptr, 0, sizeof(u64)); else - *((u64*)arp_ptr) = *((u64*)dev->dev_addr); + memcpy(arp_ptr, dev->dev_addr, sizeof(u64)); } /* Now add the ethernet header. */ @@ -1675,8 +1677,10 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) priv->bc_dgl++; } else { + __be64 guid = get_unaligned((u64 *)eth->h_dest); + node = eth1394_find_node_guid(&priv->ip_node_list, - be64_to_cpu(*(u64*)eth->h_dest)); + be64_to_cpu(guid)); if (!node) { ret = -EAGAIN; goto fail; diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index dea13525df8..6e8ea9110c4 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3552,12 +3552,21 @@ static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) { int err; + printk(KERN_INFO "%s does not fully support suspend and resume yet\n", + OHCI1394_DRIVER_NAME); + err = pci_save_state(pdev); - if (err) - goto out; + if (err) { + printk(KERN_ERR "%s: pci_save_state failed with %d\n", + OHCI1394_DRIVER_NAME, err); + return err; + } err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); +#ifdef OHCI1394_DEBUG if (err) - goto out; + printk(KERN_DEBUG "%s: pci_set_power_state failed with %d\n", + OHCI1394_DRIVER_NAME, err); +#endif /* OHCI1394_DEBUG */ /* PowerMac suspend code comes last */ #ifdef CONFIG_PPC_PMAC @@ -3570,8 +3579,8 @@ static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0); } #endif /* CONFIG_PPC_PMAC */ -out: - return err; + + return 0; } #endif /* CONFIG_PM */ diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 60d3fbdd216..e11187ecc93 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -47,6 +47,7 @@ struct addr_req { struct sockaddr src_addr; struct sockaddr dst_addr; struct rdma_dev_addr *addr; + struct rdma_addr_client *client; void *context; void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context); @@ -61,6 +62,26 @@ static LIST_HEAD(req_list); static DECLARE_WORK(work, process_req, NULL); static struct workqueue_struct *addr_wq; +void rdma_addr_register_client(struct rdma_addr_client *client) +{ + atomic_set(&client->refcount, 1); + init_completion(&client->comp); +} +EXPORT_SYMBOL(rdma_addr_register_client); + +static inline void put_client(struct rdma_addr_client *client) +{ + if (atomic_dec_and_test(&client->refcount)) + complete(&client->comp); +} + +void rdma_addr_unregister_client(struct rdma_addr_client *client) +{ + put_client(client); + wait_for_completion(&client->comp); +} +EXPORT_SYMBOL(rdma_addr_unregister_client); + int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, const unsigned char *dst_dev_addr) { @@ -229,6 +250,7 @@ static void process_req(void *data) list_del(&req->list); req->callback(req->status, &req->src_addr, req->addr, req->context); + put_client(req->client); kfree(req); } } @@ -264,7 +286,8 @@ static int addr_resolve_local(struct sockaddr_in *src_in, return ret; } -int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, +int rdma_resolve_ip(struct rdma_addr_client *client, + struct sockaddr *src_addr, struct sockaddr *dst_addr, struct rdma_dev_addr *addr, int timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), @@ -285,6 +308,8 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, req->addr = addr; req->callback = callback; req->context = context; + req->client = client; + atomic_inc(&client->refcount); src_in = (struct sockaddr_in *) &req->src_addr; dst_in = (struct sockaddr_in *) &req->dst_addr; @@ -305,6 +330,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, break; default: ret = req->status; + atomic_dec(&client->refcount); kfree(req); break; } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9ae4f3a67c7..845090b0859 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -63,6 +63,7 @@ static struct ib_client cma_client = { }; static struct ib_sa_client sa_client; +static struct rdma_addr_client addr_client; static LIST_HEAD(dev_list); static LIST_HEAD(listen_any_list); static DEFINE_MUTEX(lock); @@ -1625,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, if (cma_any_addr(dst_addr)) ret = cma_resolve_loopback(id_priv); else - ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr, - &id->route.addr.dev_addr, + ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr, + dst_addr, &id->route.addr.dev_addr, timeout_ms, addr_handler, id_priv); if (ret) goto err; @@ -1762,22 +1763,29 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) if (!cma_any_addr(addr)) { ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); - if (!ret) { - mutex_lock(&lock); - ret = cma_acquire_dev(id_priv); - mutex_unlock(&lock); - } if (ret) - goto err; + goto err1; + + mutex_lock(&lock); + ret = cma_acquire_dev(id_priv); + mutex_unlock(&lock); + if (ret) + goto err1; } memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); ret = cma_get_port(id_priv); if (ret) - goto err; + goto err2; return 0; -err: +err2: + if (!cma_any_addr(addr)) { + mutex_lock(&lock); + cma_detach_from_dev(id_priv); + mutex_unlock(&lock); + } +err1: cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); return ret; } @@ -2210,6 +2218,7 @@ static int cma_init(void) return -ENOMEM; ib_sa_register_client(&sa_client); + rdma_addr_register_client(&addr_client); ret = ib_register_client(&cma_client); if (ret) @@ -2217,6 +2226,7 @@ static int cma_init(void) return 0; err: + rdma_addr_unregister_client(&addr_client); ib_sa_unregister_client(&sa_client); destroy_workqueue(cma_wq); return ret; @@ -2225,6 +2235,7 @@ err: static void cma_cleanup(void) { ib_unregister_client(&cma_client); + rdma_addr_unregister_client(&addr_client); ib_sa_unregister_client(&sa_client); destroy_workqueue(cma_wq); idr_destroy(&sdp_ps); diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 493f4c65c7a..a72bcea46ff 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1750,7 +1750,7 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, */ (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || rcv_has_same_gid(mad_agent_priv, wr, wc))) - return wr; + return (wr->status == IB_WC_SUCCESS) ? wr : NULL; } /* diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index b72c7f69ca9..743247ec065 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1214,7 +1214,7 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file, resp.qp_access_flags = attr->qp_access_flags; resp.pkey_index = attr->pkey_index; resp.alt_pkey_index = attr->alt_pkey_index; - resp.en_sqd_async_notify = attr->en_sqd_async_notify; + resp.sq_draining = attr->sq_draining; resp.max_rd_atomic = attr->max_rd_atomic; resp.max_dest_rd_atomic = attr->max_dest_rd_atomic; resp.min_rnr_timer = attr->min_rnr_timer; diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index dc1ebeac35c..27fe242ed43 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -1155,7 +1155,8 @@ static int __devinit c2_probe(struct pci_dev *pcidev, goto bail10; } - c2_register_device(c2dev); + if (c2_register_device(c2dev)) + goto bail10; return 0; @@ -1243,7 +1244,7 @@ static struct pci_driver c2_pci_driver = { static int __init c2_init_module(void) { - return pci_module_init(&c2_pci_driver); + return pci_register_driver(&c2_pci_driver); } static void __exit c2_exit_module(void) diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/infiniband/hw/amso1100/c2_alloc.c index 028a60bbfca..0315f99e419 100644 --- a/drivers/infiniband/hw/amso1100/c2_alloc.c +++ b/drivers/infiniband/hw/amso1100/c2_alloc.c @@ -42,13 +42,14 @@ static int c2_alloc_mqsp_chunk(struct c2_dev *c2dev, gfp_t gfp_mask, { int i; struct sp_chunk *new_head; + dma_addr_t dma_addr; - new_head = (struct sp_chunk *) __get_free_page(gfp_mask); + new_head = dma_alloc_coherent(&c2dev->pcidev->dev, PAGE_SIZE, + &dma_addr, gfp_mask); if (new_head == NULL) return -ENOMEM; - new_head->dma_addr = dma_map_single(c2dev->ibdev.dma_device, new_head, - PAGE_SIZE, DMA_FROM_DEVICE); + new_head->dma_addr = dma_addr; pci_unmap_addr_set(new_head, mapping, new_head->dma_addr); new_head->next = NULL; @@ -80,10 +81,8 @@ void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root) while (root) { next = root->next; - dma_unmap_single(c2dev->ibdev.dma_device, - pci_unmap_addr(root, mapping), PAGE_SIZE, - DMA_FROM_DEVICE); - __free_page((struct page *) root); + dma_free_coherent(&c2dev->pcidev->dev, PAGE_SIZE, root, + pci_unmap_addr(root, mapping)); root = next; } } diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c index 9d7bcc5ade9..05c9154d46f 100644 --- a/drivers/infiniband/hw/amso1100/c2_cq.c +++ b/drivers/infiniband/hw/amso1100/c2_cq.c @@ -246,20 +246,17 @@ int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq) { - - dma_unmap_single(c2dev->ibdev.dma_device, pci_unmap_addr(mq, mapping), - mq->q_size * mq->msg_size, DMA_FROM_DEVICE); - free_pages((unsigned long) mq->msg_pool.host, - get_order(mq->q_size * mq->msg_size)); + dma_free_coherent(&c2dev->pcidev->dev, mq->q_size * mq->msg_size, + mq->msg_pool.host, pci_unmap_addr(mq, mapping)); } static int c2_alloc_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq, int q_size, int msg_size) { - unsigned long pool_start; + u8 *pool_start; - pool_start = __get_free_pages(GFP_KERNEL, - get_order(q_size * msg_size)); + pool_start = dma_alloc_coherent(&c2dev->pcidev->dev, q_size * msg_size, + &mq->host_dma, GFP_KERNEL); if (!pool_start) return -ENOMEM; @@ -267,13 +264,10 @@ static int c2_alloc_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq, int q_size, 0, /* index (currently unknown) */ q_size, msg_size, - (u8 *) pool_start, + pool_start, NULL, /* peer (currently unknown) */ C2_MQ_HOST_TARGET); - mq->host_dma = dma_map_single(c2dev->ibdev.dma_device, - (void *)pool_start, - q_size * msg_size, DMA_FROM_DEVICE); pci_unmap_addr_set(mq, mapping, mq->host_dma); return 0; diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index da98d9f7142..fef97275291 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -757,20 +757,17 @@ static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev) int c2_register_device(struct c2_dev *dev) { - int ret; + int ret = -ENOMEM; int i; /* Register pseudo network device */ dev->pseudo_netdev = c2_pseudo_netdev_init(dev); - if (dev->pseudo_netdev) { - ret = register_netdev(dev->pseudo_netdev); - if (ret) { - printk(KERN_ERR PFX - "Unable to register netdev, ret = %d\n", ret); - free_netdev(dev->pseudo_netdev); - return ret; - } - } + if (!dev->pseudo_netdev) + goto out3; + + ret = register_netdev(dev->pseudo_netdev); + if (ret) + goto out2; pr_debug("%s:%u\n", __FUNCTION__, __LINE__); strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX); @@ -848,21 +845,25 @@ int c2_register_device(struct c2_dev *dev) ret = ib_register_device(&dev->ibdev); if (ret) - return ret; + goto out1; for (i = 0; i < ARRAY_SIZE(c2_class_attributes); ++i) { ret = class_device_create_file(&dev->ibdev.class_dev, c2_class_attributes[i]); - if (ret) { - unregister_netdev(dev->pseudo_netdev); - free_netdev(dev->pseudo_netdev); - ib_unregister_device(&dev->ibdev); - return ret; - } + if (ret) + goto out0; } + goto out3; - pr_debug("%s:%u\n", __FUNCTION__, __LINE__); - return 0; +out0: + ib_unregister_device(&dev->ibdev); +out1: + unregister_netdev(dev->pseudo_netdev); +out2: + free_netdev(dev->pseudo_netdev); +out3: + pr_debug("%s:%u ret=%d\n", __FUNCTION__, __LINE__, ret); + return ret; } void c2_unregister_device(struct c2_dev *dev) diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c index e37c5688c21..623dc95f91d 100644 --- a/drivers/infiniband/hw/amso1100/c2_rnic.c +++ b/drivers/infiniband/hw/amso1100/c2_rnic.c @@ -150,15 +150,15 @@ static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props) (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) err = -ENOMEM; - - err = c2_errno(reply); + else + err = c2_errno(reply); if (err) goto bail2; props->fw_ver = ((u64)be32_to_cpu(reply->fw_ver_major) << 32) | - ((be32_to_cpu(reply->fw_ver_minor) && 0xFFFF) << 16) | - (be32_to_cpu(reply->fw_ver_patch) && 0xFFFF); + ((be32_to_cpu(reply->fw_ver_minor) & 0xFFFF) << 16) | + (be32_to_cpu(reply->fw_ver_patch) & 0xFFFF); memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6); props->max_mr_size = 0xFFFFFFFF; props->page_size_cap = ~(C2_MIN_PAGESIZE-1); @@ -517,14 +517,12 @@ int c2_rnic_init(struct c2_dev *c2dev) /* Initialize the Verbs Reply Queue */ qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_QSIZE)); msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_MSGSIZE)); - q1_pages = kmalloc(qsize * msgsize, GFP_KERNEL); + q1_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize, + &c2dev->rep_vq.host_dma, GFP_KERNEL); if (!q1_pages) { err = -ENOMEM; goto bail1; } - c2dev->rep_vq.host_dma = dma_map_single(c2dev->ibdev.dma_device, - (void *)q1_pages, qsize * msgsize, - DMA_FROM_DEVICE); pci_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma); pr_debug("%s rep_vq va %p dma %llx\n", __FUNCTION__, q1_pages, (unsigned long long) c2dev->rep_vq.host_dma); @@ -540,17 +538,15 @@ int c2_rnic_init(struct c2_dev *c2dev) /* Initialize the Asynchronus Event Queue */ qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_QSIZE)); msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_MSGSIZE)); - q2_pages = kmalloc(qsize * msgsize, GFP_KERNEL); + q2_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize, + &c2dev->aeq.host_dma, GFP_KERNEL); if (!q2_pages) { err = -ENOMEM; goto bail2; } - c2dev->aeq.host_dma = dma_map_single(c2dev->ibdev.dma_device, - (void *)q2_pages, qsize * msgsize, - DMA_FROM_DEVICE); pci_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma); - pr_debug("%s aeq va %p dma %llx\n", __FUNCTION__, q1_pages, - (unsigned long long) c2dev->rep_vq.host_dma); + pr_debug("%s aeq va %p dma %llx\n", __FUNCTION__, q2_pages, + (unsigned long long) c2dev->aeq.host_dma); c2_mq_rep_init(&c2dev->aeq, 2, qsize, @@ -597,17 +593,13 @@ int c2_rnic_init(struct c2_dev *c2dev) bail4: vq_term(c2dev); bail3: - dma_unmap_single(c2dev->ibdev.dma_device, - pci_unmap_addr(&c2dev->aeq, mapping), - c2dev->aeq.q_size * c2dev->aeq.msg_size, - DMA_FROM_DEVICE); - kfree(q2_pages); + dma_free_coherent(&c2dev->pcidev->dev, + c2dev->aeq.q_size * c2dev->aeq.msg_size, + q2_pages, pci_unmap_addr(&c2dev->aeq, mapping)); bail2: - dma_unmap_single(c2dev->ibdev.dma_device, - pci_unmap_addr(&c2dev->rep_vq, mapping), - c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, - DMA_FROM_DEVICE); - kfree(q1_pages); + dma_free_coherent(&c2dev->pcidev->dev, + c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, + q1_pages, pci_unmap_addr(&c2dev->rep_vq, mapping)); bail1: c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool); bail0: @@ -640,19 +632,17 @@ void c2_rnic_term(struct c2_dev *c2dev) /* Free the verbs request allocator */ vq_term(c2dev); - /* Unmap and free the asynchronus event queue */ - dma_unmap_single(c2dev->ibdev.dma_device, - pci_unmap_addr(&c2dev->aeq, mapping), - c2dev->aeq.q_size * c2dev->aeq.msg_size, - DMA_FROM_DEVICE); - kfree(c2dev->aeq.msg_pool.host); - - /* Unmap and free the verbs reply queue */ - dma_unmap_single(c2dev->ibdev.dma_device, - pci_unmap_addr(&c2dev->rep_vq, mapping), - c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, - DMA_FROM_DEVICE); - kfree(c2dev->rep_vq.msg_pool.host); + /* Free the asynchronus event queue */ + dma_free_coherent(&c2dev->pcidev->dev, + c2dev->aeq.q_size * c2dev->aeq.msg_size, + c2dev->aeq.msg_pool.host, + pci_unmap_addr(&c2dev->aeq, mapping)); + + /* Free the verbs reply queue */ + dma_free_coherent(&c2dev->pcidev->dev, + c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, + c2dev->rep_vq.msg_pool.host, + pci_unmap_addr(&c2dev->rep_vq, mapping)); /* Free the MQ shared pointer pool */ c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool); diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig index 922389b6439..727b10d8968 100644 --- a/drivers/infiniband/hw/ehca/Kconfig +++ b/drivers/infiniband/hw/ehca/Kconfig @@ -10,6 +10,7 @@ config INFINIBAND_EHCA config INFINIBAND_EHCA_SCALING bool "Scaling support (EXPERIMENTAL)" depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL + default y ---help--- eHCA scaling support schedules the CQ callbacks to different CPUs. diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c index 3bac197f901..214e2fdddee 100644 --- a/drivers/infiniband/hw/ehca/ehca_av.c +++ b/drivers/infiniband/hw/ehca/ehca_av.c @@ -118,8 +118,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) } memcpy(&av->av.grh.word_1, &gid, sizeof(gid)); } - /* for the time being we use a hard coded PMTU of 2048 Bytes */ - av->av.pmtu = 4; + av->av.pmtu = EHCA_MAX_MTU; /* dgid comes in grh.word_3 */ memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid, @@ -193,7 +192,7 @@ int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid)); } - new_ehca_av.pmtu = 4; /* see also comment in create_ah() */ + new_ehca_av.pmtu = EHCA_MAX_MTU; memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid, sizeof(ah_attr->grh.dgid)); diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index 5eae6ac4842..e1b618c5f68 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -40,6 +40,7 @@ */ #include "ehca_tools.h" +#include "ehca_iverbs.h" #include "hcp_if.h" int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) @@ -49,7 +50,7 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) ib_device); struct hipz_query_hca *rblock; - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -96,7 +97,7 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX); query_device1: - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); return ret; } @@ -109,7 +110,7 @@ int ehca_query_port(struct ib_device *ibdev, ib_device); struct hipz_query_port *rblock; - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -162,7 +163,7 @@ int ehca_query_port(struct ib_device *ibdev, props->active_speed = 0x1; query_port1: - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); return ret; } @@ -178,7 +179,7 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) return -EINVAL; } - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -193,7 +194,7 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16)); query_pkey1: - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); return ret; } @@ -211,7 +212,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, return -EINVAL; } - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -227,7 +228,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64)); query_gid1: - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); return ret; } diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 048cc443d1e..c3ea746e904 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -45,6 +45,7 @@ #include "ehca_tools.h" #include "hcp_if.h" #include "hipz_fns.h" +#include "ipz_pt_fn.h" #define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1) #define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31) @@ -137,38 +138,36 @@ int ehca_error_data(struct ehca_shca *shca, void *data, u64 *rblock; unsigned long block_count; - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_err(&shca->ib_device, "Cannot allocate rblock memory."); ret = -ENOMEM; goto error_data1; } + /* rblock must be 4K aligned and should be 4K large */ ret = hipz_h_error_data(shca->ipz_hca_handle, resource, rblock, &block_count); - if (ret == H_R_STATE) { + if (ret == H_R_STATE) ehca_err(&shca->ib_device, "No error data is available: %lx.", resource); - } else if (ret == H_SUCCESS) { int length; length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]); - if (length > PAGE_SIZE) - length = PAGE_SIZE; + if (length > EHCA_PAGESIZE) + length = EHCA_PAGESIZE; print_error_data(shca, data, rblock, length); - } - else { + } else ehca_err(&shca->ib_device, "Error data could not be fetched: %lx", resource); - } - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); error_data1: return ret; diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index 319c39d47f3..3720e3032cc 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -179,4 +179,12 @@ int ehca_mmap_register(u64 physical,void **mapped, int ehca_munmap(unsigned long addr, size_t len); +#ifdef CONFIG_PPC_64K_PAGES +void *ehca_alloc_fw_ctrlblock(void); +void ehca_free_fw_ctrlblock(void *ptr); +#else +#define ehca_alloc_fw_ctrlblock() ((void *) get_zeroed_page(GFP_KERNEL)) +#define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr)) +#endif + #endif diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 024d511c4b5..01f5aa9cb56 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -40,6 +40,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifdef CONFIG_PPC_64K_PAGES +#include <linux/slab.h> +#endif #include "ehca_classes.h" #include "ehca_iverbs.h" #include "ehca_mrmw.h" @@ -49,7 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0017"); +MODULE_VERSION("SVNEHCA_0018"); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -94,11 +97,31 @@ spinlock_t ehca_cq_idr_lock; DEFINE_IDR(ehca_qp_idr); DEFINE_IDR(ehca_cq_idr); + static struct list_head shca_list; /* list of all registered ehcas */ static spinlock_t shca_list_lock; static struct timer_list poll_eqs_timer; +#ifdef CONFIG_PPC_64K_PAGES +static struct kmem_cache *ctblk_cache = NULL; + +void *ehca_alloc_fw_ctrlblock(void) +{ + void *ret = kmem_cache_zalloc(ctblk_cache, SLAB_KERNEL); + if (!ret) + ehca_gen_err("Out of memory for ctblk"); + return ret; +} + +void ehca_free_fw_ctrlblock(void *ptr) +{ + if (ptr) + kmem_cache_free(ctblk_cache, ptr); + +} +#endif + static int ehca_create_slab_caches(void) { int ret; @@ -133,6 +156,17 @@ static int ehca_create_slab_caches(void) goto create_slab_caches5; } +#ifdef CONFIG_PPC_64K_PAGES + ctblk_cache = kmem_cache_create("ehca_cache_ctblk", + EHCA_PAGESIZE, H_CB_ALIGNMENT, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!ctblk_cache) { + ehca_gen_err("Cannot create ctblk SLAB cache."); + ehca_cleanup_mrmw_cache(); + goto create_slab_caches5; + } +#endif return 0; create_slab_caches5: @@ -157,6 +191,10 @@ static void ehca_destroy_slab_caches(void) ehca_cleanup_qp_cache(); ehca_cleanup_cq_cache(); ehca_cleanup_pd_cache(); +#ifdef CONFIG_PPC_64K_PAGES + if (ctblk_cache) + kmem_cache_destroy(ctblk_cache); +#endif } #define EHCA_HCAAVER EHCA_BMASK_IBM(32,39) @@ -168,7 +206,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) u64 h_ret; struct hipz_query_hca *rblock; - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_gen_err("Cannot allocate rblock memory."); return -ENOMEM; @@ -211,7 +249,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) shca->sport[1].rate = IB_RATE_30_GBPS; num_ports1: - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); return ret; } @@ -220,7 +258,7 @@ static int init_node_guid(struct ehca_shca *shca) int ret = 0; struct hipz_query_hca *rblock; - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + rblock = ehca_alloc_fw_ctrlblock(); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -235,7 +273,7 @@ static int init_node_guid(struct ehca_shca *shca) memcpy(&shca->ib_device.node_guid, &rblock->node_guid, sizeof(u64)); init_node_guid1: - kfree(rblock); + ehca_free_fw_ctrlblock(rblock); return ret; } @@ -431,7 +469,7 @@ static ssize_t ehca_show_##name(struct device *dev, \ \ shca = dev->driver_data; \ \ - rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); \ + rblock = ehca_alloc_fw_ctrlblock(); \ if (!rblock) { \ dev_err(dev, "Can't allocate rblock memory."); \ return 0; \ @@ -439,12 +477,12 @@ static ssize_t ehca_show_##name(struct device *dev, \ \ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \ dev_err(dev, "Can't query device properties"); \ - kfree(rblock); \ + ehca_free_fw_ctrlblock(rblock); \ return 0; \ } \ \ data = rblock->name; \ - kfree(rblock); \ + ehca_free_fw_ctrlblock(rblock); \ \ if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \ return snprintf(buf, 256, "1\n"); \ @@ -752,7 +790,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0017)\n"); + "(Rel.: SVNEHCA_0018)\n"); idr_init(&ehca_qp_idr); idr_init(&ehca_cq_idr); spin_lock_init(&ehca_qp_idr_lock); diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 5ca65441e1d..abce676c0ae 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -1013,7 +1013,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, u32 i; u64 *kpage; - kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + kpage = ehca_alloc_fw_ctrlblock(); if (!kpage) { ehca_err(&shca->ib_device, "kpage alloc failed"); ret = -ENOMEM; @@ -1092,7 +1092,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, ehca_reg_mr_rpages_exit1: - kfree(kpage); + ehca_free_fw_ctrlblock(kpage); ehca_reg_mr_rpages_exit0: if (ret) ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p " @@ -1124,7 +1124,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, ehca_mrmw_map_acl(acl, &hipz_acl); ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); - kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + kpage = ehca_alloc_fw_ctrlblock(); if (!kpage) { ehca_err(&shca->ib_device, "kpage alloc failed"); ret = -ENOMEM; @@ -1181,7 +1181,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, } ehca_rereg_mr_rereg1_exit1: - kfree(kpage); + ehca_free_fw_ctrlblock(kpage); ehca_rereg_mr_rereg1_exit0: if ( ret && (ret != -EAGAIN) ) ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x " diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 4394123cdbd..cf3e50ee2d0 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -811,8 +811,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, unsigned long spl_flags = 0; /* do query_qp to obtain current attr values */ - mqpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); - if (mqpcb == NULL) { + mqpcb = ehca_alloc_fw_ctrlblock(); + if (!mqpcb) { ehca_err(ibqp->device, "Could not get zeroed page for mqpcb " "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num); return -ENOMEM; @@ -1225,7 +1225,7 @@ modify_qp_exit2: } modify_qp_exit1: - kfree(mqpcb); + ehca_free_fw_ctrlblock(mqpcb); return ret; } @@ -1277,7 +1277,7 @@ int ehca_query_qp(struct ib_qp *qp, return -EINVAL; } - qpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL ); + qpcb = ehca_alloc_fw_ctrlblock(); if (!qpcb) { ehca_err(qp->device,"Out of memory for qpcb " "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num); @@ -1401,7 +1401,7 @@ int ehca_query_qp(struct ib_qp *qp, ehca_dmp(qpcb, 4*70, "qp_num=%x", qp->qp_num); query_qp_exit1: - kfree(qpcb); + ehca_free_fw_ctrlblock(qpcb); return ret; } diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index 809da3ef706..973c4b59154 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h @@ -63,6 +63,7 @@ #include <asm/ibmebus.h> #include <asm/io.h> #include <asm/pgtable.h> +#include <asm/hvcall.h> extern int ehca_debug_level; diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h index 3fc92b031c5..fad91368dc5 100644 --- a/drivers/infiniband/hw/ehca/hipz_hw.h +++ b/drivers/infiniband/hw/ehca/hipz_hw.h @@ -45,6 +45,8 @@ #include "ehca_tools.h" +#define EHCA_MAX_MTU 4 + /* QP Table Entry Memory Map */ struct hipz_qptemm { u64 qpx_hcr; diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/infiniband/hw/ipath/Kconfig index 574a678e7fd..90c14543677 100644 --- a/drivers/infiniband/hw/ipath/Kconfig +++ b/drivers/infiniband/hw/ipath/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_IPATH tristate "QLogic InfiniPath Driver" - depends on PCI_MSI && 64BIT && INFINIBAND + depends on (PCI_MSI || HT_IRQ) && 64BIT && INFINIBAND && NET ---help--- This is a driver for QLogic InfiniPath host channel adapters, including InfiniBand verbs support. This driver allows these diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile index 5e29cb0095e..7dc10551cf1 100644 --- a/drivers/infiniband/hw/ipath/Makefile +++ b/drivers/infiniband/hw/ipath/Makefile @@ -10,8 +10,6 @@ ib_ipath-y := \ ipath_eeprom.o \ ipath_file_ops.o \ ipath_fs.o \ - ipath_iba6110.o \ - ipath_iba6120.o \ ipath_init_chip.o \ ipath_intr.o \ ipath_keys.o \ @@ -31,5 +29,8 @@ ib_ipath-y := \ ipath_verbs_mcast.o \ ipath_verbs.o +ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o +ib_ipath-$(CONFIG_PCI_MSI) += ipath_iba6120.o + ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 29958b6e021..28c087b824c 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -67,19 +67,54 @@ static struct file_operations diag_file_ops = { .release = ipath_diag_release }; +static ssize_t ipath_diagpkt_write(struct file *fp, + const char __user *data, + size_t count, loff_t *off); + +static struct file_operations diagpkt_file_ops = { + .owner = THIS_MODULE, + .write = ipath_diagpkt_write, +}; + +static atomic_t diagpkt_count = ATOMIC_INIT(0); +static struct cdev *diagpkt_cdev; +static struct class_device *diagpkt_class_dev; + int ipath_diag_add(struct ipath_devdata *dd) { char name[16]; + int ret = 0; + + if (atomic_inc_return(&diagpkt_count) == 1) { + ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR, + "ipath_diagpkt", &diagpkt_file_ops, + &diagpkt_cdev, &diagpkt_class_dev); + + if (ret) { + ipath_dev_err(dd, "Couldn't create ipath_diagpkt " + "device: %d", ret); + goto done; + } + } snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit); - return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name, - &diag_file_ops, &dd->diag_cdev, - &dd->diag_class_dev); + ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name, + &diag_file_ops, &dd->diag_cdev, + &dd->diag_class_dev); + if (ret) + ipath_dev_err(dd, "Couldn't create %s device: %d", + name, ret); + +done: + return ret; } void ipath_diag_remove(struct ipath_devdata *dd) { + if (atomic_dec_and_test(&diagpkt_count)) + ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev); + ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev); } @@ -275,30 +310,6 @@ bail: return ret; } -static ssize_t ipath_diagpkt_write(struct file *fp, - const char __user *data, - size_t count, loff_t *off); - -static struct file_operations diagpkt_file_ops = { - .owner = THIS_MODULE, - .write = ipath_diagpkt_write, -}; - -static struct cdev *diagpkt_cdev; -static struct class_device *diagpkt_class_dev; - -int __init ipath_diagpkt_add(void) -{ - return ipath_cdev_init(IPATH_DIAGPKT_MINOR, - "ipath_diagpkt", &diagpkt_file_ops, - &diagpkt_cdev, &diagpkt_class_dev); -} - -void __exit ipath_diagpkt_remove(void) -{ - ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev); -} - /** * ipath_diagpkt_write - write an IB packet * @fp: the diag data device file pointer diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 12cefa658f3..1aeddb48e35 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -304,7 +304,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, } addr = pci_resource_start(pdev, 0); len = pci_resource_len(pdev, 0); - ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %x, vend %x/%x " + ipath_cdbg(VERBOSE, "regbase (0) %llx len %d pdev->irq %d, vend %x/%x " "driver_data %lx\n", addr, len, pdev->irq, ent->vendor, ent->device, ent->driver_data); @@ -390,12 +390,16 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, /* setup the chip-specific functions, as early as possible. */ switch (ent->device) { +#ifdef CONFIG_HT_IRQ case PCI_DEVICE_ID_INFINIPATH_HT: ipath_init_iba6110_funcs(dd); break; +#endif +#ifdef CONFIG_PCI_MSI case PCI_DEVICE_ID_INFINIPATH_PE800: ipath_init_iba6120_funcs(dd); break; +#endif default: ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, " "failing\n", ent->device); @@ -467,15 +471,15 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, * check 0 irq after we return from chip-specific bus setup, since * that can affect this due to setup */ - if (!pdev->irq) + if (!dd->ipath_irq) ipath_dev_err(dd, "irq is 0, BIOS error? Interrupts won't " "work\n"); else { - ret = request_irq(pdev->irq, ipath_intr, IRQF_SHARED, + ret = request_irq(dd->ipath_irq, ipath_intr, IRQF_SHARED, IPATH_DRV_NAME, dd); if (ret) { ipath_dev_err(dd, "Couldn't setup irq handler, " - "irq=%u: %d\n", pdev->irq, ret); + "irq=%d: %d\n", dd->ipath_irq, ret); goto bail_iounmap; } } @@ -637,11 +641,10 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev) * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs * for all versions of the driver, if they were allocated */ - if (pdev->irq) { - ipath_cdbg(VERBOSE, - "unit %u free_irq of irq %x\n", - dd->ipath_unit, pdev->irq); - free_irq(pdev->irq, dd); + if (dd->ipath_irq) { + ipath_cdbg(VERBOSE, "unit %u free irq %d\n", + dd->ipath_unit, dd->ipath_irq); + dd->ipath_f_free_irq(dd); } else ipath_dbg("irq is 0, not doing free_irq " "for unit %u\n", dd->ipath_unit); @@ -2005,18 +2008,8 @@ static int __init infinipath_init(void) goto bail_group; } - ret = ipath_diagpkt_add(); - if (ret < 0) { - printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " - "diag data device: error %d\n", -ret); - goto bail_ipathfs; - } - goto bail; -bail_ipathfs: - ipath_exit_ipathfs(); - bail_group: ipath_driver_remove_group(&ipath_driver.driver); diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index 9e4e8d4c6e2..e57c7a351cb 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -38,6 +38,7 @@ #include <linux/pci.h> #include <linux/delay.h> +#include <linux/htirq.h> #include "ipath_kernel.h" #include "ipath_registers.h" @@ -913,49 +914,40 @@ static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev, } } -static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev, - int pos) +static int ipath_ht_intconfig(struct ipath_devdata *dd) { - u32 int_handler_addr_lower; - u32 int_handler_addr_upper; - u64 ihandler; - u32 intvec; + int ret; - /* use indirection register to get the intr handler */ - pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10); - pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower); - pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11); - pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper); + if (dd->ipath_intconfig) { + ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig, + dd->ipath_intconfig); /* interrupt address */ + ret = 0; + } else { + ipath_dev_err(dd, "No interrupts enabled, couldn't setup " + "interrupt address\n"); + ret = -EINVAL; + } - ihandler = (u64) int_handler_addr_lower | - ((u64) int_handler_addr_upper << 32); + return ret; +} + +static void ipath_ht_irq_update(struct pci_dev *dev, int irq, + struct ht_irq_msg *msg) +{ + struct ipath_devdata *dd = pci_get_drvdata(dev); + u64 prev_intconfig = dd->ipath_intconfig; + + dd->ipath_intconfig = msg->address_lo; + dd->ipath_intconfig |= ((u64) msg->address_hi) << 32; /* - * kernels with CONFIG_PCI_MSI set the vector in the irq field of - * struct pci_device, so we use that to program the internal - * interrupt register (not config space) with that value. The BIOS - * must still have done the basic MSI setup. - */ - intvec = pdev->irq; - /* - * clear any vector bits there; normally not set but we'll overload - * this for some debug purposes (setting the HTC debug register - * value from software, rather than GPIOs), so it might be set on a - * driver reload. + * If the previous value of dd->ipath_intconfig is zero, we're + * getting configured for the first time, and must not program the + * intconfig register here (it will be programmed later, when the + * hardware is ready). Otherwise, we should. */ - ihandler &= ~0xff0000; - /* x86 vector goes in intrinfo[23:16] */ - ihandler |= intvec << 16; - ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, " - "interruptconfig %llx\n", int_handler_addr_lower, - int_handler_addr_upper, intvec, - (unsigned long long) ihandler); - - /* can't program yet, so save for interrupt setup */ - dd->ipath_intconfig = ihandler; - /* keep going, so we find link control stuff also */ - - return ihandler != 0; + if (prev_intconfig) + ipath_ht_intconfig(dd); } /** @@ -971,12 +963,19 @@ static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev, static int ipath_setup_ht_config(struct ipath_devdata *dd, struct pci_dev *pdev) { - int pos, ret = 0; - int ihandler = 0; + int pos, ret; + + ret = __ht_create_irq(pdev, 0, ipath_ht_irq_update); + if (ret < 0) { + ipath_dev_err(dd, "Couldn't create interrupt handler: " + "err %d\n", ret); + goto bail; + } + dd->ipath_irq = ret; + ret = 0; /* - * Read the capability info to find the interrupt info, and also - * handle clearing CRC errors in linkctrl register if necessary. We + * Handle clearing CRC errors in linkctrl register if necessary. We * do this early, before we ever enable errors or hardware errors, * mostly to avoid causing the chip to enter freeze mode. */ @@ -1000,17 +999,9 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, } if (!(cap_type & 0xE0)) slave_or_pri_blk(dd, pdev, pos, cap_type); - else if (cap_type == HT_INTR_DISC_CONFIG) - ihandler = set_int_handler(dd, pdev, pos); } while ((pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_HT))); - if (!ihandler) { - ipath_dev_err(dd, "Couldn't find interrupt handler in " - "config space\n"); - ret = -ENODEV; - } - bail: return ret; } @@ -1360,25 +1351,6 @@ static void ipath_ht_quiet_serdes(struct ipath_devdata *dd) ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); } -static int ipath_ht_intconfig(struct ipath_devdata *dd) -{ - int ret; - - if (!dd->ipath_intconfig) { - ipath_dev_err(dd, "No interrupts enabled, couldn't setup " - "interrupt address\n"); - ret = 1; - goto bail; - } - - ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig, - dd->ipath_intconfig); /* interrupt address */ - ret = 0; - -bail: - return ret; -} - /** * ipath_pe_put_tid - write a TID in chip * @dd: the infinipath device @@ -1575,6 +1547,14 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) return 0; } +static void ipath_ht_free_irq(struct ipath_devdata *dd) +{ + free_irq(dd->ipath_irq, dd); + ht_destroy_irq(dd->ipath_irq); + dd->ipath_irq = 0; + dd->ipath_intconfig = 0; +} + /** * ipath_init_iba6110_funcs - set up the chip-specific function pointers * @dd: the infinipath device @@ -1598,6 +1578,7 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd) dd->ipath_f_cleanup = ipath_setup_ht_cleanup; dd->ipath_f_setextled = ipath_setup_ht_setextled; dd->ipath_f_get_base_info = ipath_ht_get_base_info; + dd->ipath_f_free_irq = ipath_ht_free_irq; /* * initialize chip-specific variables diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index a72ab9de386..6af89683f71 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -851,6 +851,7 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd, int pos, ret; dd->ipath_msi_lo = 0; /* used as a flag during reset processing */ + dd->ipath_irq = pdev->irq; ret = pci_enable_msi(dd->pcidev); if (ret) ipath_dev_err(dd, "pci_enable_msi failed: %d, " @@ -1323,6 +1324,12 @@ done: return 0; } +static void ipath_pe_free_irq(struct ipath_devdata *dd) +{ + free_irq(dd->ipath_irq, dd); + dd->ipath_irq = 0; +} + /** * ipath_init_iba6120_funcs - set up the chip-specific function pointers * @dd: the infinipath device @@ -1349,6 +1356,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd) dd->ipath_f_cleanup = ipath_setup_pe_cleanup; dd->ipath_f_setextled = ipath_setup_pe_setextled; dd->ipath_f_get_base_info = ipath_pe_get_base_info; + dd->ipath_f_free_irq = ipath_pe_free_irq; /* initialize chip-specific variables */ dd->ipath_f_tidtemplate = ipath_pe_tidtemplate; diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index d9079ee1203..5652a550d44 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -710,14 +710,14 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp) * linuxbios development work, and it may happen in * the future again. */ - if (dd->pcidev && dd->pcidev->irq) { + if (dd->pcidev && dd->ipath_irq) { ipath_dev_err(dd, "Now %u unexpected " "interrupts, unregistering " "interrupt handler\n", *unexpectp); - ipath_dbg("free_irq of irq %x\n", - dd->pcidev->irq); - free_irq(dd->pcidev->irq, dd); + ipath_dbg("free_irq of irq %d\n", + dd->ipath_irq); + dd->ipath_f_free_irq(dd); } } if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) { @@ -753,7 +753,7 @@ static void ipath_bad_regread(struct ipath_devdata *dd) if (allbits == 2) { ipath_dev_err(dd, "Still bad interrupt status, " "unregistering interrupt\n"); - free_irq(dd->pcidev->irq, dd); + dd->ipath_f_free_irq(dd); } else if (allbits > 2) { if ((allbits % 10000) == 0) printk("."); diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 7c436697d0e..986b2125b8f 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -213,6 +213,8 @@ struct ipath_devdata { void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64); /* fill out chip-specific fields */ int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); + /* free irq */ + void (*ipath_f_free_irq)(struct ipath_devdata *); struct ipath_ibdev *verbs_dev; struct timer_list verbs_timer; /* total dwords sent (summed from counter) */ @@ -328,6 +330,8 @@ struct ipath_devdata { /* so we can rewrite it after a chip reset */ u32 ipath_pcibar1; + /* interrupt number */ + int ipath_irq; /* HT/PCI Vendor ID (here for NodeInfo) */ u16 ipath_vendorid; /* HT/PCI Device ID (here for NodeInfo) */ @@ -869,9 +873,6 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *); void ipath_device_remove_group(struct device *, struct ipath_devdata *); int ipath_expose_reset(struct device *); -int ipath_diagpkt_add(void); -void ipath_diagpkt_remove(void); - int ipath_init_ipathfs(void); void ipath_exit_ipathfs(void); int ipathfs_add_device(struct ipath_devdata *); diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 99a94d71093..768df7265b8 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1820,11 +1820,11 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, #define MAD_IFC_BOX_SIZE 0x400 #define MAD_IFC_MY_QPN_OFFSET 0x100 -#define MAD_IFC_RQPN_OFFSET 0x104 -#define MAD_IFC_SL_OFFSET 0x108 -#define MAD_IFC_G_PATH_OFFSET 0x109 -#define MAD_IFC_RLID_OFFSET 0x10a -#define MAD_IFC_PKEY_OFFSET 0x10e +#define MAD_IFC_RQPN_OFFSET 0x108 +#define MAD_IFC_SL_OFFSET 0x10c +#define MAD_IFC_G_PATH_OFFSET 0x10d +#define MAD_IFC_RLID_OFFSET 0x10e +#define MAD_IFC_PKEY_OFFSET 0x112 #define MAD_IFC_GRH_OFFSET 0x140 inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); @@ -1862,7 +1862,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, val = in_wc->dlid_path_bits | (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); - MTHCA_PUT(inbox, val, MAD_IFC_GRH_OFFSET); + MTHCA_PUT(inbox, val, MAD_IFC_G_PATH_OFFSET); MTHCA_PUT(inbox, in_wc->slid, MAD_IFC_RLID_OFFSET); MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET); @@ -1870,7 +1870,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, if (in_grh) memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40); - op_modifier |= 0x10; + op_modifier |= 0x4; in_modifier |= in_wc->slid << 16; } diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index e393681ba7d..149b3690123 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -39,6 +39,8 @@ #include <linux/init.h> #include <linux/hardirq.h> +#include <asm/io.h> + #include <rdma/ib_pack.h> #include "mthca_dev.h" @@ -210,6 +212,11 @@ static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq, mthca_write64(doorbell, dev->kar + MTHCA_CQ_DOORBELL, MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + /* + * Make sure doorbells don't leak out of CQ spinlock + * and reach the HCA out of order: + */ + mmiowb(); } } diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 5e5c58b9920..6a7822e0fc1 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -39,6 +39,8 @@ #include <linux/string.h> #include <linux/slab.h> +#include <asm/io.h> + #include <rdma/ib_verbs.h> #include <rdma/ib_cache.h> #include <rdma/ib_pack.h> @@ -1732,6 +1734,11 @@ out: mthca_write64(doorbell, dev->kar + MTHCA_SEND_DOORBELL, MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + /* + * Make sure doorbells don't leak out of SQ spinlock + * and reach the HCA out of order: + */ + mmiowb(); } qp->sq.next_ind = ind; @@ -1851,6 +1858,12 @@ out: qp->rq.next_ind = ind; qp->rq.head += nreq; + /* + * Make sure doorbells don't leak out of RQ spinlock and reach + * the HCA out of order: + */ + mmiowb(); + spin_unlock_irqrestore(&qp->rq.lock, flags); return err; } @@ -2112,6 +2125,12 @@ out: MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); } + /* + * Make sure doorbells don't leak out of SQ spinlock and reach + * the HCA out of order: + */ + mmiowb(); + spin_unlock_irqrestore(&qp->sq.lock, flags); return err; } diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 92a72f52152..f5d7677d107 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -35,6 +35,8 @@ #include <linux/slab.h> #include <linux/string.h> +#include <asm/io.h> + #include "mthca_dev.h" #include "mthca_cmd.h" #include "mthca_memfree.h" @@ -595,6 +597,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); } + /* + * Make sure doorbells don't leak out of SRQ spinlock and + * reach the HCA out of order: + */ + mmiowb(); + spin_unlock_irqrestore(&srq->lock, flags); return err; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 1eaf00e9862..85522daeb94 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -49,6 +49,8 @@ #include <net/dst.h> +#define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff) + MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("IP-over-InfiniBand net driver"); MODULE_LICENSE("Dual BSD/GPL"); @@ -520,8 +522,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, sizeof(union ib_gid)); - ipoib_send(dev, skb, path->ah, - be32_to_cpup((__be32 *) skb->dst->neighbour->ha)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); } else { neigh->ah = NULL; __skb_queue_tail(&neigh->queue, skb); @@ -599,8 +600,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ipoib_dbg(priv, "Send unicast ARP to %04x\n", be16_to_cpu(path->pathrec.dlid)); - ipoib_send(dev, skb, path->ah, - be32_to_cpup((__be32 *) phdr->hwaddr)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { /* put pseudoheader back on for next time */ @@ -661,8 +661,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) goto out; } - ipoib_send(dev, skb, neigh->ah, - be32_to_cpup((__be32 *) skb->dst->neighbour->ha)); + ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); goto out; } @@ -694,7 +693,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) IPOIB_GID_FMT "\n", skb->dst ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), - be32_to_cpup((__be32 *) phdr->hwaddr), + IPOIB_QPN(phdr->hwaddr), IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); dev_kfree_skb_any(skb); ++priv->stats.tx_dropped; @@ -777,7 +776,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) ipoib_dbg(priv, "neigh_destructor for %06x " IPOIB_GID_FMT "\n", - be32_to_cpup((__be32 *) n->ha), + IPOIB_QPN(n->ha), IPOIB_GID_RAW_ARG(n->ha + 4)); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index eb6f98d8228..9b2041e25d5 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -363,11 +363,11 @@ iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_conn *conn = cls_conn->dd_data; int err; - err = iscsi_conn_start(cls_conn); + err = iser_conn_set_full_featured_mode(conn); if (err) return err; - return iser_conn_set_full_featured_mode(conn); + return iscsi_conn_start(cls_conn); } static struct iscsi_transport iscsi_iser_transport; diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 90de5afe03c..1dec00e20db 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -82,17 +82,19 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device { struct fm801_gp *gp; struct gameport *port; + int error; gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL); port = gameport_allocate_port(); if (!gp || !port) { printk(KERN_ERR "fm801-gp: Memory allocation failed\n"); - kfree(gp); - gameport_free_port(port); - return -ENOMEM; + error = -ENOMEM; + goto err_out_free; } - pci_enable_device(pci); + error = pci_enable_device(pci); + if (error) + goto err_out_free; port->open = fm801_gp_open; #ifdef HAVE_COOKED @@ -108,9 +110,8 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device if (!gp->res_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; + error = -EBUSY; + goto err_out_disable_dev; } pci_set_drvdata(pci, gp); @@ -119,6 +120,13 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device gameport_register_port(port); return 0; + + err_out_disable_dev: + pci_disable_device(pci); + err_out_free: + gameport_free_port(port); + kfree(gp); + return error; } static void __devexit fm801_gp_remove(struct pci_dev *pci) diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 3f47ae55c6f..a0af97efe6a 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -191,6 +191,8 @@ static void gameport_run_poll_handler(unsigned long d) static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv) { + int error; + down_write(&gameport_bus.subsys.rwsem); gameport->dev.driver = &drv->driver; @@ -198,8 +200,20 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv gameport->dev.driver = NULL; goto out; } - device_bind_driver(&gameport->dev); -out: + + error = device_bind_driver(&gameport->dev); + if (error) { + printk(KERN_WARNING + "gameport: device_bind_driver() failed " + "for %s (%s) and %s, error: %d\n", + gameport->phys, gameport->name, + drv->description, error); + drv->disconnect(gameport); + gameport->dev.driver = NULL; + goto out; + } + + out: up_write(&gameport_bus.subsys.rwsem); } diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index b6ef9eaad1d..cbb93669d1c 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -221,6 +221,7 @@ struct atkbd { unsigned long xl_bit; unsigned int last; unsigned long time; + unsigned long err_count; struct work_struct event_work; struct mutex event_mutex; @@ -234,11 +235,13 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t #define ATKBD_DEFINE_ATTR(_name) \ static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ -static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ +static ssize_t atkbd_do_show_##_name(struct device *d, \ + struct device_attribute *attr, char *b) \ { \ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ } \ -static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \ +static ssize_t atkbd_do_set_##_name(struct device *d, \ + struct device_attribute *attr, const char *b, size_t s) \ { \ return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ } \ @@ -251,6 +254,32 @@ ATKBD_DEFINE_ATTR(set); ATKBD_DEFINE_ATTR(softrepeat); ATKBD_DEFINE_ATTR(softraw); +#define ATKBD_DEFINE_RO_ATTR(_name) \ +static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ +static ssize_t atkbd_do_show_##_name(struct device *d, \ + struct device_attribute *attr, char *b) \ +{ \ + return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ +} \ +static struct device_attribute atkbd_attr_##_name = \ + __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); + +ATKBD_DEFINE_RO_ATTR(err_count); + +static struct attribute *atkbd_attributes[] = { + &atkbd_attr_extra.attr, + &atkbd_attr_scroll.attr, + &atkbd_attr_set.attr, + &atkbd_attr_softrepeat.attr, + &atkbd_attr_softraw.attr, + &atkbd_attr_err_count.attr, + NULL +}; + +static struct attribute_group atkbd_attribute_group = { + .attrs = atkbd_attributes, +}; + static const unsigned int xl_table[] = { ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, @@ -396,7 +425,10 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, add_release_event = 1; break; case ATKBD_RET_ERR: + atkbd->err_count++; +#ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); +#endif goto out; } @@ -786,12 +818,7 @@ static void atkbd_disconnect(struct serio *serio) synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */ flush_scheduled_work(); - device_remove_file(&serio->dev, &atkbd_attr_extra); - device_remove_file(&serio->dev, &atkbd_attr_scroll); - device_remove_file(&serio->dev, &atkbd_attr_set); - device_remove_file(&serio->dev, &atkbd_attr_softrepeat); - device_remove_file(&serio->dev, &atkbd_attr_softraw); - + sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); input_unregister_device(atkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); @@ -961,11 +988,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - device_create_file(&serio->dev, &atkbd_attr_extra); - device_create_file(&serio->dev, &atkbd_attr_scroll); - device_create_file(&serio->dev, &atkbd_attr_set); - device_create_file(&serio->dev, &atkbd_attr_softrepeat); - device_create_file(&serio->dev, &atkbd_attr_softraw); + sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group); atkbd_enable(atkbd); @@ -1259,6 +1282,11 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co return count; } +static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf) +{ + return sprintf(buf, "%lu\n", atkbd->err_count); +} + static int __init atkbd_init(void) { diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index cb70970625b..befdd6006b5 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -207,7 +207,7 @@ static irqreturn_t corgikbd_interrupt(int irq, void *dev_id) static void corgikbd_timer_callback(unsigned long data) { struct corgikbd *corgikbd_data = (struct corgikbd *) data; - corgikbd_scankeyboard(corgikbd_data, NULL); + corgikbd_scankeyboard(corgikbd_data); } /* diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 708d5a1bc3d..979b93e33da 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -59,11 +59,6 @@ * 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 - * - * Should you need to contact me, the author, you can do so either by - * email or by paper mail: - * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), - * Germany. */ #include <linux/delay.h> diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index fd33c9cc327..5788dbc317b 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -186,7 +186,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) static void locomokbd_timer_callback(unsigned long data) { struct locomokbd *locomokbd = (struct locomokbd *) data; - locomokbd_scankeyboard(locomokbd, NULL); + locomokbd_scankeyboard(locomokbd); } static int locomokbd_probe(struct locomo_dev *dev) diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 8b18c009e3e..28b2748e82d 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -257,7 +257,7 @@ static void spitzkbd_timer_callback(unsigned long data) { struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; - spitzkbd_scankeyboard(spitzkbd_data, NULL); + spitzkbd_scankeyboard(spitzkbd_data); } /* diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 1be963961c1..ab4da79ee56 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -60,7 +60,7 @@ static struct fasync_struct *hp_sdc_rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); -static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, +static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, @@ -385,14 +385,14 @@ static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) return 0; } -static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, +static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ssize_t retval; if (count < sizeof(unsigned long)) return -EINVAL; - retval = put_user(68, (unsigned long *)buf); + retval = put_user(68, (unsigned long __user *)buf); return retval; } @@ -696,7 +696,7 @@ static int __init hp_sdc_rtc_init(void) if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) return ret; misc_register(&hp_sdc_rtc_dev); - create_proc_read_entry ("driver/rtc", 0, 0, + create_proc_read_entry ("driver/rtc", 0, NULL, hp_sdc_rtc_read_proc, NULL); printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 4639537336f..7b9d1c1da41 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -17,7 +17,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/dmi.h> #include <linux/init.h> #include <linux/input.h> diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index bdfde046b74..49e11e2c1d5 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -391,23 +391,23 @@ static int hilse_operate(hil_mlc *mlc, int repoll) { } #define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \ -{ HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc }, +{ HILSE_FUNC, { .func = funct }, funct_arg, zero_rc, neg_rc, pos_rc }, #define OUT(pack) \ -{ HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, +{ HILSE_OUT, { .packet = pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, #define CTS \ -{ HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, +{ HILSE_CTS, { .packet = 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, #define EXPECT(comp, to, got, got_wrong, timed_out) \ -{ HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out }, +{ HILSE_EXPECT, { .packet = comp }, to, got, got_wrong, timed_out }, #define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \ -{ HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out }, +{ HILSE_EXPECT_LAST, { .packet = comp }, to, got, got_wrong, timed_out }, #define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \ -{ HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out }, +{ HILSE_EXPECT_DISC, { .packet = comp }, to, got, got_wrong, timed_out }, #define IN(to, got, got_error, timed_out) \ -{ HILSE_IN, { packet: 0 }, to, got, got_error, timed_out }, +{ HILSE_IN, { .packet = 0 }, to, got, got_error, timed_out }, #define OUT_DISC(pack) \ -{ HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 }, +{ HILSE_OUT_DISC, { .packet = pack }, 0, 0, 0, 0 }, #define OUT_LAST(pack) \ -{ HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 }, +{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 }, struct hilse_node hil_mlc_se[HILSEN_END] = { diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index ba7b920347e..9907ad3bea2 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -310,7 +310,7 @@ static void hp_sdc_tasklet(unsigned long foo) { * in tasklet/bh context. */ if (curr->act.irqhook) - curr->act.irqhook(0, 0, 0, 0); + curr->act.irqhook(0, NULL, 0, 0); } curr->actidx = curr->idx; curr->idx++; @@ -525,7 +525,7 @@ actdone: up(curr->act.semaphore); } else if (act & HP_SDC_ACT_CALLBACK) { - curr->act.irqhook(0,0,0,0); + curr->act.irqhook(0,NULL,0,0); } if (curr->idx >= curr->endidx) { /* This transaction is over. */ if (act & HP_SDC_ACT_DEALLOC) kfree(curr); diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 09b06e605b5..7e3141f37e3 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -106,6 +106,7 @@ static unsigned char i8042_ctr; static unsigned char i8042_mux_present; static unsigned char i8042_kbd_irq_registered; static unsigned char i8042_aux_irq_registered; +static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; static irqreturn_t i8042_interrupt(int irq, void *dev_id); @@ -316,7 +317,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) unsigned char str, data; unsigned int dfl; unsigned int port_no; - int ret; + int ret = 1; spin_lock_irqsave(&i8042_lock, flags); str = i8042_read_status(); @@ -378,10 +379,16 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); + if (unlikely(i8042_suppress_kbd_ack)) + if (port_no == I8042_KBD_PORT_NO && + (data == 0xfa || data == 0xfe)) { + i8042_suppress_kbd_ack = 0; + goto out; + } + if (likely(port->exists)) serio_interrupt(port->serio, data, dfl); - ret = 1; out: return IRQ_RETVAL(ret); } @@ -842,11 +849,13 @@ static long i8042_panic_blink(long count) led ^= 0x01 | 0x04; while (i8042_read_status() & I8042_STR_IBF) DELAY; + i8042_suppress_kbd_ack = 1; i8042_write_data(0xed); /* set leds */ DELAY; while (i8042_read_status() & I8042_STR_IBF) DELAY; DELAY; + i8042_suppress_kbd_ack = 1; i8042_write_data(led); DELAY; last_blink = count; diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index dcb16b5cbec..e5b1b60757b 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -189,7 +189,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } - mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); + mutex_lock(&ps2dev->cmd_mutex); serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; @@ -296,6 +296,7 @@ EXPORT_SYMBOL(ps2_schedule_command); void ps2_init(struct ps2dev *ps2dev, struct serio *serio) { mutex_init(&ps2dev->cmd_mutex); + lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth); init_waitqueue_head(&ps2dev->wait); ps2dev->serio = serio; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 960fae3c3ce..211943f85cb 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -118,6 +118,8 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) { + int error; + down_write(&serio_bus.subsys.rwsem); if (serio_match_port(drv->id_table, serio)) { @@ -126,9 +128,19 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) serio->dev.driver = NULL; goto out; } - device_bind_driver(&serio->dev); + error = device_bind_driver(&serio->dev); + if (error) { + printk(KERN_WARNING + "serio: device_bind_driver() failed " + "for %s (%s) and %s, error: %d\n", + serio->phys, serio->name, + drv->description, error); + serio_disconnect_driver(serio); + serio->dev.driver = NULL; + goto out; + } } -out: + out: up_write(&serio_bus.subsys.rwsem); } @@ -538,8 +550,12 @@ static void serio_init_port(struct serio *serio) "serio%ld", (long)atomic_inc_return(&serio_no) - 1); serio->dev.bus = &serio_bus; serio->dev.release = serio_release_port; - if (serio->parent) + if (serio->parent) { serio->dev.parent = &serio->parent->dev; + serio->depth = serio->parent->depth + 1; + } else + serio->depth = 0; + lockdep_set_subclass(&serio->lock, serio->depth); } /* diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index ca79b224619..66121f6a89a 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -219,7 +219,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer) static void corgi_ts_timer(unsigned long data) { struct corgi_ts *corgits_data = (struct corgi_ts *) data; - ts_interrupt_main(corgits_data, 1, NULL); + ts_interrupt_main(corgits_data, 1); } static irqreturn_t ts_interrupt(int irq, void *dev_id) @@ -237,7 +237,7 @@ static int corgits_suspend(struct platform_device *dev, pm_message_t state) if (corgi_ts->pendown) { del_timer_sync(&corgi_ts->timer); corgi_ts->tc.pressure = 0; - new_data(corgi_ts, NULL); + new_data(corgi_ts); corgi_ts->pendown = 0; } corgi_ts->power_mode = PWR_MODE_SUSPEND; diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c index e31c6c55b2e..58fca316786 100644 --- a/drivers/input/touchscreen/hp680_ts_input.c +++ b/drivers/input/touchscreen/hp680_ts_input.c @@ -6,7 +6,7 @@ #include <asm/io.h> #include <asm/delay.h> #include <asm/adc.h> -#include <asm/hp6xx/hp6xx.h> +#include <asm/hp6xx.h> #define MODNAME "hp680_ts_input" diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index d10c8b82e6a..b6f9476c050 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -1907,7 +1907,8 @@ static int if_readstat(u8 __user *buf, int len, int id, int channel) } for (p=buf, count=0; count < len; p++, count++) { - put_user(*card->q931_read++, p); + if (put_user(*card->q931_read++, p)) + return -EFAULT; if (card->q931_read > card->q931_end) card->q931_read = card->q931_buf; } diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index aca165d43aa..5800beeebb8 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -616,7 +616,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else { - dev_warn(cs->dev, "could not allocate skb\n"); + warn("could not allocate skb\n"); bcs->inputstate |= INS_skip_frame; } diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index eb57a988e04..cfd2718a490 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -344,7 +344,7 @@ config HISAX_HFC_SX config HISAX_ENTERNOW_PCI bool "Formula-n enter:now PCI card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) + depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Formula-n enter:now PCI ISDN card. diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index e4823ab2b12..785b08554fc 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -631,7 +631,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) count = cs->status_end - cs->status_read + 1; if (count >= len) count = len; - copy_to_user(p, cs->status_read, count); + if (copy_to_user(p, cs->status_read, count)) + return -EFAULT; cs->status_read += count; if (cs->status_read > cs->status_end) cs->status_read = cs->status_buf; @@ -642,7 +643,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) cnt = HISAX_STATUS_BUFSIZE; else cnt = count; - copy_to_user(p, cs->status_read, cnt); + if (copy_to_user(p, cs->status_read, cnt)) + return -EFAULT; p += cnt; cs->status_read += cnt % HISAX_STATUS_BUFSIZE; count -= cnt; diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 7e95f04f13d..3dacfff93f5 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -716,8 +716,10 @@ release_io_diva(struct IsdnCardState *cs) *cfg = 0; /* disable INT0/1 */ *cfg = 2; /* reset pending INT0 */ - iounmap((void *)cs->hw.diva.cfg_reg); - iounmap((void *)cs->hw.diva.pci_cfg); + if (cs->hw.diva.cfg_reg) + iounmap((void *)cs->hw.diva.cfg_reg); + if (cs->hw.diva.pci_cfg) + iounmap((void *)cs->hw.diva.pci_cfg); return; } else if (cs->subtyp != DIVA_IPAC_ISA) { del_timer(&cs->hw.diva.tl); @@ -734,6 +736,23 @@ release_io_diva(struct IsdnCardState *cs) } static void +iounmap_diva(struct IsdnCardState *cs) +{ + if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) { + if (cs->hw.diva.cfg_reg) { + iounmap((void *)cs->hw.diva.cfg_reg); + cs->hw.diva.cfg_reg = 0; + } + if (cs->hw.diva.pci_cfg) { + iounmap((void *)cs->hw.diva.pci_cfg); + cs->hw.diva.pci_cfg = 0; + } + } + + return; +} + +static void reset_diva(struct IsdnCardState *cs) { if (cs->subtyp == DIVA_IPAC_ISA) { @@ -1069,11 +1088,13 @@ setup_diva(struct IsdnCard *card) if (!cs->irq) { printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + iounmap_diva(cs); return(0); } if (!cs->hw.diva.cfg_reg) { printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + iounmap_diva(cs); return(0); } cs->irq_flags |= IRQF_SHARED; @@ -1123,6 +1144,7 @@ ready: CardType[card->typ], cs->hw.diva.cfg_reg, cs->hw.diva.cfg_reg + bytecnt); + iounmap_diva(cs); return (0); } } diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 160f22fa594..82e42a80dc4 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -45,11 +45,10 @@ ergo_interrupt(int intno, void *dev_id) if (!card->irq_enabled) return IRQ_NONE; /* other device interrupting or irq switched off */ - save_flags(flags); - cli(); /* no further irqs allowed */ + spin_lock_irqsave(&card->hysdn_lock, flags); /* no further irqs allowed */ if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) { - restore_flags(flags); /* restore old state */ + spin_unlock_irqrestore(&card->hysdn_lock, flags); /* restore old state */ return IRQ_NONE; /* no interrupt requested by E1 */ } /* clear any pending ints on the board */ @@ -61,7 +60,7 @@ ergo_interrupt(int intno, void *dev_id) /* start kernel task immediately after leaving all interrupts */ if (!card->hw_lock) schedule_work(&card->irq_queue); - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); return IRQ_HANDLED; } /* ergo_interrupt */ @@ -83,10 +82,9 @@ ergo_irq_bh(hysdn_card * card) dpr = card->dpram; /* point to DPRAM */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); if (card->hw_lock) { - restore_flags(flags); /* hardware currently unavailable */ + spin_unlock_irqrestore(&card->hysdn_lock, flags); /* hardware currently unavailable */ return; } card->hw_lock = 1; /* we now lock the hardware */ @@ -120,7 +118,7 @@ ergo_irq_bh(hysdn_card * card) card->hw_lock = 0; /* free hardware again */ } while (again); /* until nothing more to do */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); } /* ergo_irq_bh */ @@ -137,8 +135,7 @@ ergo_stopcard(hysdn_card * card) #ifdef CONFIG_HYSDN_CAPI hycapi_capi_stop(card); #endif /* CONFIG_HYSDN_CAPI */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */ byteout(card->iobase + PCI9050_INTR_REG, val); @@ -147,7 +144,7 @@ ergo_stopcard(hysdn_card * card) card->state = CARD_STATE_UNUSED; card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); } /* ergo_stopcard */ /**************************************************************************/ @@ -162,12 +159,11 @@ ergo_set_errlog_state(hysdn_card * card, int on) card->err_log_state = ERRLOG_STATE_OFF; /* must be off */ return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) || ((card->err_log_state == ERRLOG_STATE_ON) && on)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); return; /* nothing to do */ } if (on) @@ -175,7 +171,7 @@ ergo_set_errlog_state(hysdn_card * card, int on) else card->err_log_state = ERRLOG_STATE_STOP; /* request stop */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); schedule_work(&card->irq_queue); } /* ergo_set_errlog_state */ @@ -356,8 +352,7 @@ ergo_waitpofready(struct HYSDN_CARD *card) if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "ERGO: pof boot success"); - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); card->state = CARD_STATE_RUN; /* now card is running */ /* enable the cards interrupt */ @@ -370,7 +365,7 @@ ergo_waitpofready(struct HYSDN_CARD *card) dpr->ToHyInt = 1; dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); if ((hynet_enable & (1 << card->myid)) && (i = hysdn_net_create(card))) { @@ -408,7 +403,7 @@ ergo_releasehardware(hysdn_card * card) free_irq(card->irq, card); /* release interrupt */ release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */ release_region(card->iobase + PCI9050_USER_IO, 1); - vfree(card->dpram); + iounmap(card->dpram); card->dpram = NULL; /* release shared mem */ } /* ergo_releasehardware */ @@ -448,6 +443,7 @@ ergo_inithardware(hysdn_card * card) card->waitpofready = ergo_waitpofready; card->set_errlog_state = ergo_set_errlog_state; INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card); + card->hysdn_lock = SPIN_LOCK_UNLOCKED; return (0); } /* ergo_inithardware */ diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index 461e831592d..729df408938 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -188,6 +188,8 @@ typedef struct HYSDN_CARD { /* init and deinit stopcard for booting, too */ void (*stopcard) (struct HYSDN_CARD *); void (*releasehardware) (struct HYSDN_CARD *); + + spinlock_t hysdn_lock; #ifdef CONFIG_HYSDN_CAPI struct hycapictrl_info { char cardname[32]; diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index c4301e8338e..fcd49920b22 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -116,8 +116,7 @@ put_log_buffer(hysdn_card * card, char *cp) strcpy(ib->log_start, cp); /* set output string */ ib->next = NULL; ib->proc_ctrl = pd; /* point to own control structure */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); ib->usage_cnt = pd->if_used; if (!pd->log_head) pd->log_head = ib; /* new head */ @@ -125,7 +124,7 @@ put_log_buffer(hysdn_card * card, char *cp) pd->log_tail->next = ib; /* follows existing messages */ pd->log_tail = ib; /* new tail */ i = pd->del_lock++; /* get lock state */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); /* delete old entrys */ if (!i) @@ -270,14 +269,13 @@ hysdn_log_open(struct inode *ino, struct file *filep) } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { /* read access -> log/debug read */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); pd->if_used++; if (pd->log_head) filep->private_data = &pd->log_tail->next; else filep->private_data = &pd->log_head; - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); } else { /* simultaneous read/write access forbidden ! */ unlock_kernel(); return (-EPERM); /* no permission this time */ @@ -301,7 +299,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) hysdn_card *card; int retval = 0; unsigned long flags; - + spinlock_t hysdn_lock = SPIN_LOCK_UNLOCKED; lock_kernel(); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { @@ -311,8 +309,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) /* read access -> log/debug read, mark one further file as closed */ pd = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&hysdn_lock, flags); inf = *((struct log_data **) filep->private_data); /* get first log entry */ if (inf) pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ @@ -335,7 +332,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) inf->usage_cnt--; /* decrement usage count for buffers */ inf = inf->next; } - restore_flags(flags); + spin_unlock_irqrestore(&hysdn_lock, flags); if (pd) if (pd->if_used <= 0) /* delete buffers if last file closed */ diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index 1c0d54ac12a..18758772b74 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -155,22 +155,17 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); - save_flags(flags); - cli(); while (card->async_busy) { - sti(); if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg delayed"); msleep_interruptible(20); /* Timeout 20ms */ - if (!--cnt) { - restore_flags(flags); + if (!--cnt) return (-ERR_ASYNC_TIME); /* timed out */ - } - cli(); } /* wait for buffer to become free */ + spin_lock_irqsave(&card->hysdn_lock, flags); strcpy(card->async_data, line); card->async_len = strlen(line) + 1; card->async_channel = chan; @@ -178,30 +173,23 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) /* now queue the task */ schedule_work(&card->irq_queue); - sti(); + spin_unlock_irqrestore(&card->hysdn_lock, flags); if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg data queued"); cnt++; /* short delay */ - cli(); while (card->async_busy) { - sti(); if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg waiting for tx-ready"); msleep_interruptible(20); /* Timeout 20ms */ - if (!--cnt) { - restore_flags(flags); + if (!--cnt) return (-ERR_ASYNC_TIME); /* timed out */ - } - cli(); } /* wait for buffer to become free again */ - restore_flags(flags); - if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg data send"); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index c3d79eef9e3..69aee2602aa 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1134,9 +1134,12 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off) if (dev->drv[drvidx]->interface->readstat) { if (count > dev->drv[drvidx]->stavail) count = dev->drv[drvidx]->stavail; - len = dev->drv[drvidx]->interface-> - readstat(buf, count, drvidx, - isdn_minor2chan(minor)); + len = dev->drv[drvidx]->interface->readstat(buf, count, + drvidx, isdn_minor2chan(minor)); + if (len < 0) { + retval = len; + goto out; + } } else { len = 0; } diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 6649f8bc995..730bbd07ebc 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1010,7 +1010,8 @@ icn_readstatus(u_char __user *buf, int len, icn_card * card) for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - put_user(*card->msg_buf_read++, p); + if (put_user(*card->msg_buf_read++, p)) + return -EFAULT; if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index fabbd461603..c3ae2edaf6f 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -100,12 +100,11 @@ isdnloop_pollbchan(unsigned long data) isdnloop_bchan_send(card, 1); if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) { /* schedule b-channel polling again */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; add_timer(&card->rb_timer); card->flags |= ISDNLOOP_FLAGS_RBTIMER; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } else card->flags &= ~ISDNLOOP_FLAGS_RBTIMER; } @@ -281,8 +280,7 @@ isdnloop_putmsg(isdnloop_card * card, unsigned char c) { ulong flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; if (card->msg_buf_write == card->msg_buf_read) { if (++card->msg_buf_read > card->msg_buf_end) @@ -290,7 +288,7 @@ isdnloop_putmsg(isdnloop_card * card, unsigned char c) } if (card->msg_buf_write > card->msg_buf_end) card->msg_buf_write = card->msg_buf; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -372,21 +370,19 @@ isdnloop_polldchan(unsigned long data) if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) { /* schedule b-channel polling */ card->flags |= ISDNLOOP_FLAGS_RBTIMER; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); del_timer(&card->rb_timer); card->rb_timer.function = isdnloop_pollbchan; card->rb_timer.data = (unsigned long) card; card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; add_timer(&card->rb_timer); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* schedule again */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; add_timer(&card->st_timer); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -416,8 +412,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card) return 0; if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); nskb = dev_alloc_skb(skb->len); if (nskb) { memcpy(skb_put(nskb, len), skb->data, len); @@ -426,7 +421,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card) } else len = 0; card->sndcount[channel] += len; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } return len; } @@ -451,7 +446,8 @@ isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card * card) for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - put_user(*card->msg_buf_read++, p); + if (put_user(*card->msg_buf_read++, p)) + return -EFAULT; if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } @@ -576,8 +572,7 @@ isdnloop_atimeout(isdnloop_card * card, int ch) unsigned long flags; char buf[60]; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); if (card->rcard) { isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1); card->rcard[ch]->rcard[card->rch[ch]] = NULL; @@ -587,7 +582,7 @@ isdnloop_atimeout(isdnloop_card * card, int ch) /* No user responding */ sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3)); isdnloop_fake(card, buf, ch + 1); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -622,8 +617,7 @@ isdnloop_start_ctimer(isdnloop_card * card, int ch) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); init_timer(&card->c_timer[ch]); card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT; if (ch) @@ -632,7 +626,7 @@ isdnloop_start_ctimer(isdnloop_card * card, int ch) card->c_timer[ch].function = isdnloop_atimeout0; card->c_timer[ch].data = (unsigned long) card; add_timer(&card->c_timer[ch]); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -647,10 +641,9 @@ isdnloop_kill_ctimer(isdnloop_card * card, int ch) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); del_timer(&card->c_timer[ch]); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } static u_char si2bit[] = @@ -706,13 +699,12 @@ isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd) } } if (num_match) { - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); /* channel idle? */ if (!(cc->rcard[ch])) { /* Check SI */ if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return 3; } /* ch is idle, si and number matches */ @@ -720,10 +712,10 @@ isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd) cc->rch[ch] = lch; card->rcard[lch] = cc; card->rch[lch] = ch; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return 0; } else { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); /* num matches, but busy */ if (ch == 1) return 1; @@ -1027,8 +1019,7 @@ isdnloop_stopcard(isdnloop_card * card) unsigned long flags; isdn_ctrl cmd; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); if (card->flags & ISDNLOOP_FLAGS_RUNNING) { card->flags &= ~ISDNLOOP_FLAGS_RUNNING; del_timer(&card->st_timer); @@ -1039,7 +1030,7 @@ isdnloop_stopcard(isdnloop_card * card) cmd.driver = card->myid; card->interface.statcallb(&cmd); } - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -1078,18 +1069,17 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) return -EBUSY; if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); switch (sdef.ptype) { case ISDN_PTYPE_EURO: if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96", -1)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } card->sil[0] = card->sil[1] = 4; if (isdnloop_fake(card, "TEI OK", 0)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } for (i = 0; i < 3; i++) @@ -1098,12 +1088,12 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) case ISDN_PTYPE_1TR6: if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95", -1)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } card->sil[0] = card->sil[1] = 4; if (isdnloop_fake(card, "TEI OK", 0)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } strcpy(card->s0num[0], sdef.num[0]); @@ -1111,7 +1101,7 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) card->s0num[2][0] = '\0'; break; default: - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n", sdef.ptype); return -EINVAL; @@ -1122,7 +1112,7 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) card->st_timer.data = (unsigned long) card; add_timer(&card->st_timer); card->flags |= ISDNLOOP_FLAGS_RUNNING; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return 0; } @@ -1472,6 +1462,7 @@ isdnloop_initcard(char *id) skb_queue_head_init(&card->bqueue[i]); } skb_queue_head_init(&card->dqueue); + card->isdnloop_lock = SPIN_LOCK_UNLOCKED; card->next = cards; cards = card; if (!register_isdn(&card->interface)) { diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h index d699fe53e1c..0d458a86f52 100644 --- a/drivers/isdn/isdnloop/isdnloop.h +++ b/drivers/isdn/isdnloop/isdnloop.h @@ -94,6 +94,7 @@ typedef struct isdnloop_card { struct sk_buff_head bqueue[ISDNLOOP_BCH]; /* B-Channel queues */ struct sk_buff_head dqueue; /* D-Channel queue */ + spinlock_t isdnloop_lock; } isdnloop_card; /* diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 94f21486bb2..6ead5e1508b 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -725,23 +725,27 @@ static int pcbit_stat(u_char __user *buf, int len, int driver, int channel) if (stat_st < stat_end) { - copy_to_user(buf, statbuf + stat_st, len); + if (copy_to_user(buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; } else { if (len > STATBUF_LEN - stat_st) { - copy_to_user(buf, statbuf + stat_st, - STATBUF_LEN - stat_st); - copy_to_user(buf, statbuf, - len - (STATBUF_LEN - stat_st)); + if (copy_to_user(buf, statbuf + stat_st, + STATBUF_LEN - stat_st)) + return -EFAULT; + if (copy_to_user(buf, statbuf, + len - (STATBUF_LEN - stat_st))) + return -EFAULT; stat_st = len - (STATBUF_LEN - stat_st); } else { - copy_to_user(buf, statbuf + stat_st, len); + if (copy_to_user(buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 13e7d219d1c..937fd212038 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -311,6 +311,7 @@ pcbit_deliver(void *data) dev->read_queue = frame->next; spin_unlock_irqrestore(&dev->lock, flags); + msg = 0; SET_MSG_CPU(msg, 0); SET_MSG_PROC(msg, 0); SET_MSG_CMD(msg, frame->skb->data[2]); diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index 222ca7c08ba..06c9872e8c6 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -98,13 +98,14 @@ static int __init sc_init(void) * Confirm the I/O Address with a test */ if(io[b] == 0) { - pr_debug("I/O Address 0x%x is in use.\n"); + pr_debug("I/O Address invalid.\n"); continue; } outb(0x18, io[b] + 0x400 * EXP_PAGE0); if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { - pr_debug("I/O Base 0x%x fails test\n"); + pr_debug("I/O Base 0x%x fails test\n", + io[b] + 0x400 * EXP_PAGE0); continue; } } @@ -158,8 +159,8 @@ static int __init sc_init(void) outb(0xFF, io[b] + RESET_OFFSET); msleep_interruptible(10000); } - pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b], - ram[b] == 0 ? "will" : "won't"); + pr_debug("RAM Base for board %d is 0x%lx, %s probe\n", b, + ram[b], ram[b] == 0 ? "will" : "won't"); if(ram[b]) { /* @@ -168,7 +169,7 @@ static int __init sc_init(void) * board model */ if(request_region(ram[b], SRAM_PAGESIZE, "sc test")) { - pr_debug("request_region for RAM base 0x%x succeeded\n", ram[b]); + pr_debug("request_region for RAM base 0x%lx succeeded\n", ram[b]); model = identify_board(ram[b], io[b]); release_region(ram[b], SRAM_PAGESIZE); } @@ -204,7 +205,7 @@ static int __init sc_init(void) * Nope, there was no place in RAM for the * board, or it couldn't be identified */ - pr_debug("Failed to find an adapter at 0x%x\n", ram[b]); + pr_debug("Failed to find an adapter at 0x%lx\n", ram[b]); continue; } @@ -451,7 +452,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) HWConfig_pl hwci; int x; - pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n", + pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n", rambase, iobase); /* @@ -490,7 +491,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) outb(PRI_BASEPG_VAL, pgport); msleep_interruptible(1000); sig = readl(rambase + SIG_OFFSET); - pr_debug("Looking for a signature, got 0x%x\n", sig); + pr_debug("Looking for a signature, got 0x%lx\n", sig); if(sig == SIGNATURE) return PRI_BOARD; @@ -500,7 +501,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) outb(BRI_BASEPG_VAL, pgport); msleep_interruptible(1000); sig = readl(rambase + SIG_OFFSET); - pr_debug("Looking for a signature, got 0x%x\n", sig); + pr_debug("Looking for a signature, got 0x%lx\n", sig); if(sig == SIGNATURE) return BRI_BOARD; @@ -510,7 +511,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) * Try to spot a card */ sig = readl(rambase + SIG_OFFSET); - pr_debug("Looking for a signature, got 0x%x\n", sig); + pr_debug("Looking for a signature, got 0x%lx\n", sig); if(sig != SIGNATURE) return -1; @@ -540,7 +541,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN); pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status); memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl)); - pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n" + pr_debug("Hardware Config: Interface: %s, RAM Size: %ld, Serial: %s\n" " Part: %s, Rev: %s\n", hwci.st_u_sense ? "S/T" : "U", hwci.ram_size, hwci.serial_no, hwci.part_no, hwci.rev_no); diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c index f50defc38ae..1e04676b016 100644 --- a/drivers/isdn/sc/packet.c +++ b/drivers/isdn/sc/packet.c @@ -44,7 +44,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data) return -ENODEV; } - pr_debug("%s: sndpkt: frst = 0x%x nxt = %d f = %d n = %d\n", + pr_debug("%s: sndpkt: frst = 0x%lx nxt = %d f = %d n = %d\n", sc_adapter[card]->devicename, sc_adapter[card]->channel[channel].first_sendbuf, sc_adapter[card]->channel[channel].next_sendbuf, @@ -66,7 +66,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data) ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf * BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf; ReqLnkWrite.msg_len = data->len; /* sk_buff size */ - pr_debug("%s: writing %d bytes to buffer offset 0x%x\n", + pr_debug("%s: writing %d bytes to buffer offset 0x%lx\n", sc_adapter[card]->devicename, ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset); memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len); @@ -74,7 +74,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data) /* * sendmessage */ - pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n", + pr_debug("%s: sndpkt size=%d, buf_offset=0x%lx buf_indx=%d\n", sc_adapter[card]->devicename, ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset, sc_adapter[card]->channel[channel].next_sendbuf); @@ -124,7 +124,7 @@ void rcvpkt(int card, RspMessage *rcvmsg) return; } skb_put(skb, rcvmsg->msg_data.response.msg_len); - pr_debug("%s: getting data from offset: 0x%x\n", + pr_debug("%s: getting data from offset: 0x%lx\n", sc_adapter[card]->devicename, rcvmsg->msg_data.response.buff_offset); memcpy_fromshmem(card, @@ -143,7 +143,7 @@ void rcvpkt(int card, RspMessage *rcvmsg) /* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */ newll.buff_offset = rcvmsg->msg_data.response.buff_offset; newll.msg_len = BUFFER_SIZE; - pr_debug("%s: recycled buffer at offset 0x%x size %d\n", + pr_debug("%s: recycled buffer at offset 0x%lx size %d\n", sc_adapter[card]->devicename, newll.buff_offset, newll.msg_len); sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead, @@ -186,7 +186,7 @@ int setup_buffers(int card, int c) sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2; sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2; sc_adapter[card]->channel[c-1].next_sendbuf = 0; - pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n", + pr_debug("%s: send buffer setup complete: first=0x%lx n=%d f=%d, nxt=%d\n", sc_adapter[card]->devicename, sc_adapter[card]->channel[c-1].first_sendbuf, sc_adapter[card]->channel[c-1].num_sendbufs, @@ -203,7 +203,7 @@ int setup_buffers(int card, int c) ((sc_adapter[card]->channel[c-1].first_sendbuf + (nBuffers / 2) * buffer_size) + (buffer_size * i)); RcvBuffOffset.msg_len = buffer_size; - pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n", + pr_debug("%s: adding RcvBuffer #%d offset=0x%lx sz=%d bufsz:%d\n", sc_adapter[card]->devicename, i + 1, RcvBuffOffset.buff_offset, RcvBuffOffset.msg_len,buffer_size); diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c index 24854826ca4..6f58862992d 100644 --- a/drivers/isdn/sc/shmem.c +++ b/drivers/isdn/sc/shmem.c @@ -61,7 +61,7 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n) spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename, ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80); - pr_debug("%s: copying %d bytes from %#x to %#x\n", + pr_debug("%s: copying %d bytes from %#lx to %#lx\n", sc_adapter[card]->devicename, n, (unsigned long) src, sc_adapter[card]->rambase + ((unsigned long) dest %0x4000)); diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index aecbbe2e89a..3c1711210e3 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -91,6 +91,8 @@ EXPORT_SYMBOL_GPL(led_classdev_resume); */ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) { + int rc; + led_cdev->class_dev = class_device_create(leds_class, NULL, 0, parent, "%s", led_cdev->name); if (unlikely(IS_ERR(led_cdev->class_dev))) @@ -99,8 +101,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) class_set_devdata(led_cdev->class_dev, led_cdev); /* register the attributes */ - class_device_create_file(led_cdev->class_dev, - &class_device_attr_brightness); + rc = class_device_create_file(led_cdev->class_dev, + &class_device_attr_brightness); + if (rc) + goto err_out; /* add to the list of leds */ write_lock(&leds_list_lock); @@ -110,16 +114,28 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) #ifdef CONFIG_LEDS_TRIGGERS rwlock_init(&led_cdev->trigger_lock); - led_trigger_set_default(led_cdev); + rc = class_device_create_file(led_cdev->class_dev, + &class_device_attr_trigger); + if (rc) + goto err_out_led_list; - class_device_create_file(led_cdev->class_dev, - &class_device_attr_trigger); + led_trigger_set_default(led_cdev); #endif printk(KERN_INFO "Registered led device: %s\n", led_cdev->class_dev->class_id); return 0; + +#ifdef CONFIG_LEDS_TRIGGERS +err_out_led_list: + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_brightness); + list_del(&led_cdev->node); +#endif +err_out: + class_device_unregister(led_cdev->class_dev); + return rc; } EXPORT_SYMBOL_GPL(led_classdev_register); diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index 179c2876b54..29a8818a32e 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -123,6 +123,7 @@ static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show, static void timer_trig_activate(struct led_classdev *led_cdev) { struct timer_trig_data *timer_data; + int rc; timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); if (!timer_data) @@ -134,10 +135,21 @@ static void timer_trig_activate(struct led_classdev *led_cdev) timer_data->timer.function = led_timer_function; timer_data->timer.data = (unsigned long) led_cdev; - class_device_create_file(led_cdev->class_dev, + rc = class_device_create_file(led_cdev->class_dev, &class_device_attr_delay_on); - class_device_create_file(led_cdev->class_dev, + if (rc) goto err_out; + rc = class_device_create_file(led_cdev->class_dev, &class_device_attr_delay_off); + if (rc) goto err_out_delayon; + + return; + +err_out_delayon: + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_delay_on); +err_out: + led_cdev->trigger_data = NULL; + kfree(timer_data); } static void timer_trig_deactivate(struct led_classdev *led_cdev) diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index fa4b13f8936..b3fbb45bc90 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -685,6 +685,17 @@ static int __init wf_pm112_init(void) ++nr_cores; printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n"); + +#ifdef MODULE + request_module("windfarm_smu_controls"); + request_module("windfarm_smu_sensors"); + request_module("windfarm_smu_sat"); + request_module("windfarm_lm75_sensor"); + request_module("windfarm_max6690_sensor"); + request_module("windfarm_cpufreq_clamp"); + +#endif /* MODULE */ + platform_driver_register(&wf_pm112_driver); return 0; } diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 2a944851b8e..f24fa734046 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -788,6 +788,7 @@ static int __init wf_smu_init(void) request_module("windfarm_smu_controls"); request_module("windfarm_smu_sensors"); request_module("windfarm_lm75_sensor"); + request_module("windfarm_cpufreq_clamp"); #endif /* MODULE */ platform_driver_register(&wf_smu_driver); diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 9961a67b4f8..26eee69ebe6 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -719,6 +719,7 @@ static int __init wf_smu_init(void) request_module("windfarm_smu_controls"); request_module("windfarm_smu_sensors"); request_module("windfarm_lm75_sensor"); + request_module("windfarm_cpufreq_clamp"); #endif /* MODULE */ platform_driver_register(&wf_smu_driver); diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c index 09baa43b259..da862e4632d 100644 --- a/drivers/mca/mca-bus.c +++ b/drivers/mca/mca-bus.c @@ -100,6 +100,7 @@ static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL); int __init mca_register_device(int bus, struct mca_device *mca_dev) { struct mca_bus *mca_bus = mca_root_busses[bus]; + int rc; mca_dev->dev.parent = &mca_bus->dev; mca_dev->dev.bus = &mca_bus_type; @@ -108,13 +109,23 @@ int __init mca_register_device(int bus, struct mca_device *mca_dev) mca_dev->dev.dma_mask = &mca_dev->dma_mask; mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask; - if (device_register(&mca_dev->dev)) - return 0; + rc = device_register(&mca_dev->dev); + if (rc) + goto err_out; - device_create_file(&mca_dev->dev, &dev_attr_id); - device_create_file(&mca_dev->dev, &dev_attr_pos); + rc = device_create_file(&mca_dev->dev, &dev_attr_id); + if (rc) goto err_out_devreg; + rc = device_create_file(&mca_dev->dev, &dev_attr_pos); + if (rc) goto err_out_id; return 1; + +err_out_id: + device_remove_file(&mca_dev->dev, &dev_attr_id); +err_out_devreg: + device_unregister(&mca_dev->dev); +err_out: + return 0; } /* */ @@ -130,13 +141,16 @@ struct mca_bus * __devinit mca_attach_bus(int bus) return NULL; } - mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL); + mca_bus = kzalloc(sizeof(struct mca_bus), GFP_KERNEL); if (!mca_bus) return NULL; - memset(mca_bus, 0, sizeof(struct mca_bus)); + sprintf(mca_bus->dev.bus_id,"mca%d",bus); sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary"); - device_register(&mca_bus->dev); + if (device_register(&mca_bus->dev)) { + kfree(mca_bus); + return NULL; + } mca_root_busses[bus] = mca_bus; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 8e67634e79a..d6f614738bb 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -536,7 +536,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) " "-- forcing full recovery\n", bmname(bitmap), events, (unsigned long long) bitmap->mddev->events); - sb->state |= BITMAP_STALE; + sb->state |= cpu_to_le32(BITMAP_STALE); } success: /* assign fields using values from superblock */ @@ -544,11 +544,11 @@ success: bitmap->daemon_sleep = daemon_sleep; bitmap->daemon_lastrun = jiffies; bitmap->max_write_behind = write_behind; - bitmap->flags |= sb->state; + bitmap->flags |= le32_to_cpu(sb->state); if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN) bitmap->flags |= BITMAP_HOSTENDIAN; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); - if (sb->state & BITMAP_STALE) + if (sb->state & cpu_to_le32(BITMAP_STALE)) bitmap->events_cleared = bitmap->mddev->events; err = 0; out: @@ -578,9 +578,9 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, spin_unlock_irqrestore(&bitmap->lock, flags); sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); switch (op) { - case MASK_SET: sb->state |= bits; + case MASK_SET: sb->state |= cpu_to_le32(bits); break; - case MASK_UNSET: sb->state &= ~bits; + case MASK_UNSET: sb->state &= cpu_to_le32(~bits); break; default: BUG(); } @@ -1413,7 +1413,7 @@ int bitmap_create(mddev_t *mddev) int err; sector_t start; - BUG_ON(sizeof(bitmap_super_t) != 256); + BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */ return 0; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 655d816760e..08a40f4e4f6 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/crypto.h> #include <linux/workqueue.h> +#include <linux/backing-dev.h> #include <asm/atomic.h> #include <linux/scatterlist.h> #include <asm/page.h> @@ -602,7 +603,7 @@ static void process_write(struct crypt_io *io) /* out of memory -> run queues */ if (remaining) - blk_congestion_wait(bio_data_dir(clone), HZ/100); + congestion_wait(bio_data_dir(clone), HZ/100); } } @@ -914,8 +915,6 @@ static int crypt_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { struct crypt_config *cc = (struct crypt_config *) ti->private; - const char *cipher; - const char *chainmode = NULL; unsigned int sz = 0; switch (type) { @@ -924,14 +923,11 @@ static int crypt_status(struct dm_target *ti, status_type_t type, break; case STATUSTYPE_TABLE: - cipher = crypto_blkcipher_name(cc->tfm); - - chainmode = cc->chainmode; - if (cc->iv_mode) - DMEMIT("%s-%s-%s ", cipher, chainmode, cc->iv_mode); + DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode, + cc->iv_mode); else - DMEMIT("%s-%s ", cipher, chainmode); + DMEMIT("%s-%s ", cc->cipher, cc->chainmode); if (cc->key_size > 0) { if ((maxlen - sz) < ((cc->key_size << 1) + 1)) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index d13bb15a8a0..4510ad8f971 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -606,9 +606,14 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) return __get_name_cell(param->name); md = dm_get_md(huge_decode_dev(param->dev)); - if (md) - mdptr = dm_get_mdptr(md); + if (!md) + goto out; + mdptr = dm_get_mdptr(md); + if (!mdptr) + dm_put(md); + +out: return mdptr; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 659224cb7c5..48a653b3f51 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -24,6 +24,7 @@ static struct workqueue_struct *_kmirrord_wq; static struct work_struct _kmirrord_work; +static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped); static inline void wake(void) { @@ -83,6 +84,7 @@ struct region_hash { struct list_head *buckets; spinlock_t region_lock; + atomic_t recovery_in_flight; struct semaphore recovery_count; struct list_head clean_regions; struct list_head quiesced_regions; @@ -191,6 +193,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms, spin_lock_init(&rh->region_lock); sema_init(&rh->recovery_count, 0); + atomic_set(&rh->recovery_in_flight, 0); INIT_LIST_HEAD(&rh->clean_regions); INIT_LIST_HEAD(&rh->quiesced_regions); INIT_LIST_HEAD(&rh->recovered_regions); @@ -382,6 +385,8 @@ static void rh_update_states(struct region_hash *rh) rh->log->type->clear_region(rh->log, reg->key); rh->log->type->complete_resync_work(rh->log, reg->key, 1); dispatch_bios(rh->ms, ®->delayed_bios); + if (atomic_dec_and_test(&rh->recovery_in_flight)) + wake_up_all(&_kmirrord_recovery_stopped); up(&rh->recovery_count); mempool_free(reg, rh->region_pool); } @@ -502,11 +507,21 @@ static int __rh_recovery_prepare(struct region_hash *rh) static void rh_recovery_prepare(struct region_hash *rh) { - while (!down_trylock(&rh->recovery_count)) + /* Extra reference to avoid race with rh_stop_recovery */ + atomic_inc(&rh->recovery_in_flight); + + while (!down_trylock(&rh->recovery_count)) { + atomic_inc(&rh->recovery_in_flight); if (__rh_recovery_prepare(rh) <= 0) { + atomic_dec(&rh->recovery_in_flight); up(&rh->recovery_count); break; } + } + + /* Drop the extra reference */ + if (atomic_dec_and_test(&rh->recovery_in_flight)) + wake_up_all(&_kmirrord_recovery_stopped); } /* @@ -1177,6 +1192,11 @@ static void mirror_postsuspend(struct dm_target *ti) struct dirty_log *log = ms->rh.log; rh_stop_recovery(&ms->rh); + + /* Wait for all I/O we generated to complete */ + wait_event(_kmirrord_recovery_stopped, + !atomic_read(&ms->rh.recovery_in_flight)); + if (log->type->suspend && log->type->suspend(log)) /* FIXME: need better error handling */ DMWARN("log suspend failed"); diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c index c5a16c55012..6f9fcd4db9b 100644 --- a/drivers/md/dm-round-robin.c +++ b/drivers/md/dm-round-robin.c @@ -136,7 +136,7 @@ static int rr_add_path(struct path_selector *ps, struct path *path, path->pscontext = pi; - list_add(&pi->list, &s->valid_paths); + list_add_tail(&pi->list, &s->valid_paths); return 0; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b5764a86c8b..fc4f743f3b5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1285,7 +1285,7 @@ int dm_suspend(struct mapped_device *md, int do_lockfs) down(&md->suspend_lock); if (dm_suspended(md)) - goto out; + goto out_unlock; map = dm_get_table(md); @@ -1361,6 +1361,8 @@ out: } dm_table_put(map); + +out_unlock: up(&md->suspend_lock); return r; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 57fa64f93e5..8cbf9c9df1c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -974,12 +974,13 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) * version 1 superblock */ -static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) +static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb) { - unsigned int disk_csum, csum; + __le32 disk_csum; + u32 csum; unsigned long long newcsum; int size = 256 + le32_to_cpu(sb->max_dev)*2; - unsigned int *isuper = (unsigned int*)sb; + __le32 *isuper = (__le32*)sb; int i; disk_csum = sb->sb_csum; @@ -989,7 +990,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) newcsum += le32_to_cpu(*isuper++); if (size == 2) - newcsum += le16_to_cpu(*(unsigned short*) isuper); + newcsum += le16_to_cpu(*(__le16*) isuper); csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; @@ -1106,7 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) if (le32_to_cpu(sb->chunksize)) rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1); - if (le32_to_cpu(sb->size) > rdev->size*2) + if (le64_to_cpu(sb->size) > rdev->size*2) return -EINVAL; return ret; } @@ -1228,7 +1229,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) else sb->resync_offset = cpu_to_le64(0); - sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors); + sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors)); sb->raid_disks = cpu_to_le32(mddev->raid_disks); sb->size = cpu_to_le64(mddev->size<<1); @@ -2002,6 +2003,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi kobject_init(&rdev->kobj); rdev->desc_nr = -1; + rdev->saved_raid_disk = -1; rdev->flags = 0; rdev->data_offset = 0; rdev->sb_events = 0; @@ -3198,6 +3200,7 @@ static int do_md_run(mddev_t * mddev) mddev->changed = 1; md_new_event(mddev); + kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE); return 0; } @@ -4043,11 +4046,8 @@ static int update_size(mddev_t *mddev, unsigned long size) return -EBUSY; ITERATE_RDEV(mddev,rdev,tmp) { sector_t avail; - if (rdev->sb_offset > rdev->data_offset) - avail = (rdev->sb_offset*2) - rdev->data_offset; - else - avail = get_capacity(rdev->bdev->bd_disk) - - rdev->data_offset; + avail = rdev->size * 2; + if (fit && (size == 0 || size > avail/2)) size = avail/2; if (avail < ((sector_t)size << 1)) @@ -4486,6 +4486,7 @@ static int md_thread(void * arg) * many dirty RAID5 blocks. */ + current->flags |= PF_NOFREEZE; allow_signal(SIGKILL); while (!kthread_should_stop()) { @@ -4502,7 +4503,6 @@ static int md_thread(void * arg) test_bit(THREAD_WAKEUP, &thread->flags) || kthread_should_stop(), thread->timeout); - try_to_freeze(); clear_bit(THREAD_WAKEUP, &thread->flags); @@ -4912,6 +4912,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait) } static struct file_operations md_seq_fops = { + .owner = THIS_MODULE, .open = md_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 171ff41b52b..14da37fee37 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -277,6 +277,7 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); conf->working_disks--; + mddev->degraded++; printk(KERN_ALERT "multipath: IO failure on %s," " disabling IO path. \n Operation continuing" " on %d IO paths.\n", @@ -336,6 +337,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); conf->working_disks++; + mddev->degraded--; rdev->raid_disk = path; set_bit(In_sync, &rdev->flags); rcu_assign_pointer(p->rdev, rdev); @@ -501,7 +503,7 @@ static int multipath_run (mddev_t *mddev) mdname(mddev)); goto out_free_conf; } - mddev->degraded = conf->raid_disks = conf->working_disks; + mddev->degraded = conf->raid_disks - conf->working_disks; conf->pool = mempool_create_kzalloc_pool(NR_RESERVED_BUFS, sizeof(struct multipath_bh)); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index dc9d2def027..656fae912fe 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1474,8 +1474,8 @@ static void fix_read_error(conf_t *conf, int read_disk, "raid1:%s: read error corrected " "(%d sectors at %llu on %s)\n", mdname(mddev), s, - (unsigned long long)sect + - rdev->data_offset, + (unsigned long long)(sect + + rdev->data_offset), bdevname(rdev->bdev, b)); } } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1250f0eab4a..7492d6033ac 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1470,8 +1470,8 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) "raid10:%s: read error corrected" " (%d sectors at %llu on %s)\n", mdname(mddev), s, - (unsigned long long)sect+ - rdev->data_offset, + (unsigned long long)(sect+ + rdev->data_offset), bdevname(rdev->bdev, b)); rdev_dec_pending(rdev, mddev); @@ -2079,7 +2079,7 @@ static int run(mddev_t *mddev) disk = conf->mirrors + i; if (!disk->rdev || - !test_bit(In_sync, &rdev->flags)) { + !test_bit(In_sync, &disk->rdev->flags)) { disk->head_position = 0; mddev->degraded++; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e14f4578072..69c3e201fa3 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3659,7 +3659,7 @@ static void end_reshape(raid5_conf_t *conf) bdev = bdget_disk(conf->mddev->gendisk, 0); if (bdev) { mutex_lock(&bdev->bd_inode->i_mutex); - i_size_write(bdev->bd_inode, conf->mddev->array_size << 10); + i_size_write(bdev->bd_inode, (loff_t)conf->mddev->array_size << 10); mutex_unlock(&bdev->bd_inode->i_mutex); bdput(bdev); } diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index d9953f7a8b6..5297a365c92 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -217,11 +217,9 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d } /* wait until we get a transfer done or error */ timeout = jiffies + HZ/100 + 1; /* 10ms */ + /* first read usually delivers bogus results... */ + saa7146_i2c_status(dev); while(1) { - /** - * first read usually delivers bogus results... - */ - saa7146_i2c_status(dev); status = saa7146_i2c_status(dev); if ((status & 0x3) != 1) break; @@ -232,10 +230,10 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n")); return -EIO; } - if ((++trial < 20) && short_delay) + if (++trial < 50 && short_delay) udelay(10); else - msleep(1); + msleep(1); } } diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 2853ea1bdaf..87fb75f0d1c 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -246,7 +246,7 @@ static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb, wIndex = (chipaddr << 8 ) | addr; deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req, - ((wValue && 0xff) << 8),wValue >> 8,((wIndex && 0xff) << 8),wIndex >> 8); + wValue & 0xff, wValue >> 8, wIndex & 0xff, wIndex >> 8); len = usb_control_msg(fc_usb->udev,pipe, req, diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index fb6c4cc8477..14e69a736ed 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -665,6 +665,10 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) case BTTV_BOARD_TWINHAN_DST: /* DST is not a frontend driver !!! */ state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL); + if (!state) { + printk("dvb_bt8xx: No memory\n"); + break; + } /* Setup the Card */ state->config = &dst_config; state->i2c = card->i2c_adapter; diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig index e46eae3b9be..1990eda10c4 100644 --- a/drivers/media/dvb/dvb-core/Kconfig +++ b/drivers/media/dvb/dvb-core/Kconfig @@ -19,6 +19,6 @@ config DVB_CORE_ATTACH allow the card drivers to only load the frontend modules they require. This saves several KBytes of memory. - Note: You will need moudule-init-tools v3.2 or later for this feature. + Note: You will need module-init-tools v3.2 or later for this feature. If unsure say Y. diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 2cc5caa26a0..a263b3f3c21 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -26,7 +26,7 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. @@ -34,7 +34,7 @@ config DVB_USB_DIBUSB_MB tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" depends on DVB_USB select DVB_DIB3000MB - select DVB_TUNER_MT2060 + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. @@ -55,7 +55,7 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. @@ -70,7 +70,7 @@ config DVB_USB_DIB0700 tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB @@ -87,7 +87,7 @@ config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. @@ -153,7 +153,7 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index fd3a9902f98..5143e426d28 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -169,7 +169,7 @@ EXPORT_SYMBOL(dibusb_read_eeprom_byte); // Config Adjacent channels Perf -cal22 static struct dibx000_agc_config dib3000p_mt2060_agc_config = { .band_caps = BAND_VHF | BAND_UHF, - .setup = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0), + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), .agc1_max = 48497, .agc1_min = 23593, @@ -196,10 +196,14 @@ static struct dib3000mc_config stk3000p_dib3000p_config = { .ln_adc_level = 0x1cc7, .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, }; static struct dibx000_agc_config dib3000p_panasonic_agc_config = { - .setup = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0), + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), .agc1_max = 56361, .agc1_min = 22282, @@ -226,6 +230,9 @@ static struct dib3000mc_config mod3000p_dib3000p_config = { .ln_adc_level = 0x1cc7, .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, }; int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h index 5153fb943da..b6078103274 100644 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ b/drivers/media/dvb/dvb-usb/dibusb.h @@ -99,7 +99,9 @@ struct dibusb_state { struct dib_fe_xfer_ops ops; int mt2060_present; +}; +struct dibusb_device_state { /* for RC5 remote control */ int old_toggle; int last_repeat_count; diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index a9219bf69b8..a58874c790b 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -75,7 +75,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; u16 raw; int i; - struct dibusb_state *st = d->priv; + struct dibusb_device_state *st = d->priv; dvb_usb_generic_rw(d,cmd,2,key,5,0); @@ -184,6 +184,7 @@ static struct dvb_usb_device_properties nova_t_properties = { .size_of_priv = sizeof(struct dibusb_state), } }, + .size_of_priv = sizeof(struct dibusb_device_state), .power_ctrl = dibusb2_0_power_ctrl, .read_mac_address = nova_t_read_mac_address, diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 080fa257a0b..aebb8d6f26f 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -276,6 +276,8 @@ config DVB_TDA826X config DVB_TUNER_MT2060 tristate "Microtune MT2060 silicon IF tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE help A driver for the silicon IF tuner MT2060 from Microtune. diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h index 6dfa839a702..7e4f95e1734 100644 --- a/drivers/media/dvb/frontends/bcm3510.h +++ b/drivers/media/dvb/frontends/bcm3510.h @@ -34,7 +34,7 @@ struct bcm3510_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if defined(CONFIG_DVB_BCM3510) || defined(CONFIG_DVB_BCM3510_MODULE) +#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE)) extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h index 10286cc29fb..7ac33690cdc 100644 --- a/drivers/media/dvb/frontends/cx22700.h +++ b/drivers/media/dvb/frontends/cx22700.h @@ -31,7 +31,7 @@ struct cx22700_config u8 demod_address; }; -#if defined(CONFIG_DVB_CX22700) || defined(CONFIG_DVB_CX22700_MODULE) +#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE)) extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index bc217ddf02c..9cd64da6ee4 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -41,7 +41,7 @@ struct cx22702_config u8 output_mode; }; -#if defined(CONFIG_DVB_CX22702) || defined(CONFIG_DVB_CX22702_MODULE) +#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) && defined(MODULE)) extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index c9d5ae250eb..0ca3af4db51 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h @@ -41,7 +41,7 @@ static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) { return r; } -#if defined(CONFIG_DVB_CX24110) || defined(CONFIG_DVB_CX24110_MODULE) +#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h index 57a1dae1dc4..84f9e4f5c15 100644 --- a/drivers/media/dvb/frontends/cx24123.h +++ b/drivers/media/dvb/frontends/cx24123.h @@ -35,7 +35,7 @@ struct cx24123_config int lnb_polarity; }; -#if defined(CONFIG_DVB_CX24123) || defined(CONFIG_DVB_CX24123_MODULE) +#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE)) extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h index 0caac3f0f27..a6d3854a67b 100644 --- a/drivers/media/dvb/frontends/dib3000.h +++ b/drivers/media/dvb/frontends/dib3000.h @@ -41,7 +41,7 @@ struct dib_fe_xfer_ops int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); }; -#if defined(CONFIG_DVB_DIB3000MB) || defined(CONFIG_DVB_DIB3000MB_MODULE) +#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE)) extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); #else diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index ccc813b525d..3561a777568 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -345,7 +345,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) /* agc */ dib3000mc_write_word(state, 36, state->cfg->max_time); - dib3000mc_write_word(state, 37, agc->setup); + dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0)); dib3000mc_write_word(state, 38, state->cfg->pwm3_value); dib3000mc_write_word(state, 39, state->cfg->ln_adc_level); diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h index b198cd5b184..72d4757601d 100644 --- a/drivers/media/dvb/frontends/dib3000mc.h +++ b/drivers/media/dvb/frontends/dib3000mc.h @@ -28,6 +28,9 @@ struct dib3000mc_config { u16 max_time; u16 ln_adc_level; + u8 agc_command1 :1; + u8 agc_command2 :1; + u8 mobile_mode; u8 output_mpeg2_in_188_bytes; @@ -36,7 +39,7 @@ struct dib3000mc_config { #define DEFAULT_DIB3000MC_I2C_ADDRESS 16 #define DEFAULT_DIB3000P_I2C_ADDRESS 24 -#if defined(CONFIG_DVB_DIB3000MC) || defined(CONFIG_DVB_DIB3000MC_MODULE) +#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) extern struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg); #else static inline struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg) diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h index 1916e3eb2df..ea7f78a7d3c 100644 --- a/drivers/media/dvb/frontends/isl6421.h +++ b/drivers/media/dvb/frontends/isl6421.h @@ -39,7 +39,7 @@ #define ISL6421_ISEL1 0x20 #define ISL6421_DCL 0x40 -#if defined(CONFIG_DVB_ISL6421) || defined(CONFIG_DVB_ISL6421_MODULE) +#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE)) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, u8 override_set, u8 override_clear); diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h index 21ba4a23076..cd15f76ff28 100644 --- a/drivers/media/dvb/frontends/l64781.h +++ b/drivers/media/dvb/frontends/l64781.h @@ -31,7 +31,7 @@ struct l64781_config u8 demod_address; }; -#if defined(CONFIG_DVB_L64781) || defined(CONFIG_DVB_L64781_MODULE) +#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE)) extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h index 3f96b485584..995059004b1 100644 --- a/drivers/media/dvb/frontends/lgdt330x.h +++ b/drivers/media/dvb/frontends/lgdt330x.h @@ -52,7 +52,7 @@ struct lgdt330x_config int clock_polarity_flip; }; -#if defined(CONFIG_DVB_LGDT330X) || defined(CONFIG_DVB_LGDT330X_MODULE) +#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE)) extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h index 1fe1dd17931..68906acf7d6 100644 --- a/drivers/media/dvb/frontends/lnbp21.h +++ b/drivers/media/dvb/frontends/lnbp21.h @@ -39,7 +39,7 @@ #include <linux/dvb/frontend.h> -#if defined(CONFIG_DVB_LNBP21) || defined(CONFIG_DVB_LNBP21_MODULE) +#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) && defined(MODULE)) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear); #else diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/dvb/frontends/mt2060.h index 34a37c2b556..0a86eab3a95 100644 --- a/drivers/media/dvb/frontends/mt2060.h +++ b/drivers/media/dvb/frontends/mt2060.h @@ -30,6 +30,14 @@ struct mt2060_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; +#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); +#else +static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2060 #endif diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h index 7112fb4d58a..cf9a1505ad4 100644 --- a/drivers/media/dvb/frontends/mt312.h +++ b/drivers/media/dvb/frontends/mt312.h @@ -34,7 +34,7 @@ struct mt312_config u8 demod_address; }; -#if defined(CONFIG_DVB_MT312) || defined(CONFIG_DVB_MT312_MODULE) +#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h index 0035c2e2d7c..e9964081fd8 100644 --- a/drivers/media/dvb/frontends/mt352.h +++ b/drivers/media/dvb/frontends/mt352.h @@ -51,7 +51,7 @@ struct mt352_config int (*demod_init)(struct dvb_frontend* fe); }; -#if defined(CONFIG_DVB_MT352) || defined(CONFIG_DVB_MT352_MODULE) +#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h index 2eb220e9806..28bc5591b31 100644 --- a/drivers/media/dvb/frontends/nxt200x.h +++ b/drivers/media/dvb/frontends/nxt200x.h @@ -45,7 +45,7 @@ struct nxt200x_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -#if defined(CONFIG_DVB_NXT200X) || defined(CONFIG_DVB_NXT200X_MODULE) +#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE)) extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h index 9397393a6bd..13d22518356 100644 --- a/drivers/media/dvb/frontends/nxt6000.h +++ b/drivers/media/dvb/frontends/nxt6000.h @@ -33,7 +33,7 @@ struct nxt6000_config u8 clock_inversion:1; }; -#if defined(CONFIG_DVB_NXT6000) || defined(CONFIG_DVB_NXT6000_MODULE) +#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE)) extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h index 9718be4fb83..add24f0a743 100644 --- a/drivers/media/dvb/frontends/or51132.h +++ b/drivers/media/dvb/frontends/or51132.h @@ -34,7 +34,7 @@ struct or51132_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -#if defined(CONFIG_DVB_OR51132) || defined(CONFIG_DVB_OR51132_MODULE) +#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE)) extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h index 10a5419f9e0..8aad8402d61 100644 --- a/drivers/media/dvb/frontends/or51211.h +++ b/drivers/media/dvb/frontends/or51211.h @@ -37,7 +37,7 @@ struct or51211_config void (*sleep)(struct dvb_frontend * fe); }; -#if defined(CONFIG_DVB_OR51211) || defined(CONFIG_DVB_OR51211_MODULE) +#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE)) extern struct dvb_frontend* or51211_attach(const struct or51211_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h index efc54d7f3c5..1555870f722 100644 --- a/drivers/media/dvb/frontends/s5h1420.h +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -34,7 +34,7 @@ struct s5h1420_config u8 invert:1; }; -#if defined(CONFIG_DVB_S5H1420) || defined(CONFIG_DVB_S5H1420_MODULE) +#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h index 4cf27d3b10f..909cefe7139 100644 --- a/drivers/media/dvb/frontends/sp8870.h +++ b/drivers/media/dvb/frontends/sp8870.h @@ -35,7 +35,7 @@ struct sp8870_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE) +#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE)) extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h index cab7ea644df..7ee78d7d916 100644 --- a/drivers/media/dvb/frontends/sp887x.h +++ b/drivers/media/dvb/frontends/sp887x.h @@ -17,7 +17,7 @@ struct sp887x_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if defined(CONFIG_DVB_SP887X) || defined(CONFIG_DVB_SP887X_MODULE) +#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE)) extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h index 760b80db43a..69f4515df2b 100644 --- a/drivers/media/dvb/frontends/stv0297.h +++ b/drivers/media/dvb/frontends/stv0297.h @@ -42,7 +42,7 @@ struct stv0297_config u8 stop_during_read:1; }; -#if defined(CONFIG_DVB_STV0297) || defined(CONFIG_DVB_STV0297_MODULE) +#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE)) extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 7ef25207081..33df9495908 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -89,7 +89,7 @@ struct stv0299_config int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); }; -#if defined(CONFIG_DVB_STV0299) || defined(CONFIG_DVB_STV0299_MODULE) +#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h index d68ae20c841..e3da780108f 100644 --- a/drivers/media/dvb/frontends/tda10021.h +++ b/drivers/media/dvb/frontends/tda10021.h @@ -32,7 +32,7 @@ struct tda10021_config u8 demod_address; }; -#if defined(CONFIG_DVB_TDA10021) || defined(CONFIG_DVB_TDA10021_MODULE) +#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct i2c_adapter* i2c, u8 pwm); #else diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index e28fca05734..605ad2dfc09 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -71,7 +71,7 @@ struct tda1004x_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if defined(CONFIG_DVB_TDA1004X) || defined(CONFIG_DVB_TDA1004X_MODULE) +#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c); diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h index e8061db1112..ed584a8f4a8 100644 --- a/drivers/media/dvb/frontends/tda10086.h +++ b/drivers/media/dvb/frontends/tda10086.h @@ -35,7 +35,16 @@ struct tda10086_config u8 invert; }; +#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TDA10086 #endif // TDA10086_H diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h index aae15bdce6e..2d3307999f2 100644 --- a/drivers/media/dvb/frontends/tda8083.h +++ b/drivers/media/dvb/frontends/tda8083.h @@ -35,7 +35,7 @@ struct tda8083_config u8 demod_address; }; -#if defined(CONFIG_DVB_TDA8083) || defined(CONFIG_DVB_TDA8083_MODULE) +#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c index eeab26bd36e..34815b0b97e 100644 --- a/drivers/media/dvb/frontends/tda826x.c +++ b/drivers/media/dvb/frontends/tda826x.c @@ -121,7 +121,7 @@ static struct dvb_tuner_ops tda826x_tuner_ops = { .info = { .name = "Philips TDA826X", .frequency_min = 950000, - .frequency_min = 2175000 + .frequency_max = 2175000 }, .release = tda826x_release, .sleep = tda826x_sleep, diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h index 3307607632b..ad998119596 100644 --- a/drivers/media/dvb/frontends/tda826x.h +++ b/drivers/media/dvb/frontends/tda826x.h @@ -35,6 +35,19 @@ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector. * @return FE pointer on success, NULL on failure. */ -extern struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough); - -#endif +#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + int has_loopthrough); +#else +static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c, + int has_loopthrough) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TDA826X + +#endif // __DVB_TDA826X_H__ diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb/frontends/tua6100.h index 8f98033ffa7..03a665e7df6 100644 --- a/drivers/media/dvb/frontends/tua6100.h +++ b/drivers/media/dvb/frontends/tua6100.h @@ -34,7 +34,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_DVB_TUA6100) || defined(CONFIG_DVB_TUA6100_MODULE) +#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE)) extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); #else static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h index f0c9dded39d..e4a2a324046 100644 --- a/drivers/media/dvb/frontends/ves1820.h +++ b/drivers/media/dvb/frontends/ves1820.h @@ -41,7 +41,7 @@ struct ves1820_config u8 selagc:1; }; -#if defined(CONFIG_DVB_VES1820) || defined(CONFIG_DVB_VES1820_MODULE) +#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE)) extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, struct i2c_adapter* i2c, u8 pwm); #else diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h index 395fed39b28..d507f8966f8 100644 --- a/drivers/media/dvb/frontends/ves1x93.h +++ b/drivers/media/dvb/frontends/ves1x93.h @@ -40,7 +40,7 @@ struct ves1x93_config u8 invert_pwm:1; }; -#if defined(CONFIG_DVB_VES1X93) || defined(CONFIG_DVB_VES1X93_MODULE) +#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE)) extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h index 79a947215c4..0bc0109737f 100644 --- a/drivers/media/dvb/frontends/zl10353.h +++ b/drivers/media/dvb/frontends/zl10353.h @@ -36,7 +36,7 @@ struct zl10353_config int parallel_ts; }; -#if defined(CONFIG_DVB_ZL10353) || defined(CONFIG_DVB_ZL10353_MODULE) +#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE)) extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 2a2e9b40061..cd5ec489af1 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -46,7 +46,14 @@ #include "bsbe1.h" #include "bsru6.h" -#define DEBIADDR_IR 0x1234 +/* + * Regarding DEBIADDR_IR: + * Some CI modules hang if random addresses are read. + * Using address 0x4000 for the IR read means that we + * use the same address as for CI version, which should + * be a safe default. + */ +#define DEBIADDR_IR 0x4000 #define DEBIADDR_CICONTROL 0x0000 #define DEBIADDR_CIVERSION 0x4000 #define DEBIADDR_IO 0x1000 @@ -1028,6 +1035,7 @@ static void frontend_init(struct budget_ci *budget_ci) case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) budget_ci->tuner_pll_address = 0x60; + philips_tdm1316l_config.invert = 1; budget_ci->budget.dvb_frontend = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index afb734df6e0..bf267552941 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -186,7 +186,7 @@ config VIDEO_KS0127 config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" - depends on VIDEO_V4L1 + depends on VIDEO_V4L1 && I2C ---help--- Support for the Philips SAA7110 video decoders. @@ -677,6 +677,8 @@ config VIDEO_M32R_AR_M64278 menu "V4L USB devices" depends on USB && VIDEO_DEV +source "drivers/media/video/pvrusb2/Kconfig" + source "drivers/media/video/em28xx/Kconfig" source "drivers/media/video/usbvideo/Kconfig" diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index a84903e0d81..21ebe8f1381 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -4001,7 +4001,7 @@ static void __devinit init_PXC200(struct bttv *btv) * - sleep 1ms * - write 0x0E * read from GPIO_DATA into buf (uint_32) - * - if ( buf>>18 & 0x01 ) || ( buf>>19 && 0x01 != 0 ) + * - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 ) * error. ERROR_CPLD_Check_Failed. */ /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index 48014a254e1..f85f2084324 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -235,6 +235,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ 0, 0, 0, 0 }; + int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60); int i; fmt = arg; @@ -246,13 +247,25 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) if ((cx25840_read(client, 0x404) & 0x10) == 0) break; - for (i = 7; i <= 23; i++) { - u8 v = cx25840_read(client, 0x424 + i - 7); + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx25840_read(client, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= + svbi->service_lines[0][i] | svbi->service_lines[1][i]; + } + } + else { + for (i = 10; i <= 21; i++) { + u8 v = cx25840_read(client, 0x424 + i - 10); - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= - svbi->service_lines[0][i] | svbi->service_lines[1][i]; + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= + svbi->service_lines[0][i] | svbi->service_lines[1][i]; + } } break; } diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index af71d4225c7..f764a57c56b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1230,6 +1230,7 @@ struct cx88_board cx88_boards[] = { .vmux = 2, .gpio0 = 0x84bf, }}, + .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_NORWOOD_MICRO] = { .name = "Norwood Micro TV Tuner", @@ -1590,6 +1591,18 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x9000, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, + },{ + .subvendor = 0x0070, + .subdevice = 0x1400, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x0070, + .subdevice = 0x1401, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x0070, + .subdevice = 0x1402, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1633,7 +1646,15 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) /* Make sure we support the board model */ switch (tv.model) { + case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */ + case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */ + case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */ + case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */ + case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */ + case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */ case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */ + case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */ + case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */ case 28552: /* WinTV-PVR 'Roslyn' (No IR) */ case 34519: /* WinTV-PCI-FM */ case 90002: /* Nova-T-PCI (9002) */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index bd0c8797f26..0ef13e7efa2 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -315,15 +315,22 @@ static struct cx22702_config hauppauge_novat_config = { .demod_address = 0x43, .output_mode = CX22702_SERIAL_OUTPUT, }; + static struct cx22702_config hauppauge_hvr1100_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; + static struct cx22702_config hauppauge_hvr1300_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; +static struct cx22702_config hauppauge_hvr3000_config = { + .demod_address = 0x63, + .output_mode = CX22702_SERIAL_OUTPUT, +}; + static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { @@ -558,6 +565,16 @@ static int dvb_register(struct cx8802_dev *dev) &dvb_pll_fmd1216me); } break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr3000_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_fmd1216me); + } + break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 83ebf7a3c05..57e1c024a54 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -196,18 +196,25 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: - case CX88_BOARD_WINFAST2000XP_EXPERT: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; ir->mask_keyup = 0x100; ir->polling = 50; /* ms */ break; + case CX88_BOARD_WINFAST2000XP_EXPERT: + ir_codes = ir_codes_winfast; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0x8f8; + ir->mask_keyup = 0x100; + ir->polling = 1; /* ms */ + break; case CX88_BOARD_IODATA_GVBCTV7E: ir_codes = ir_codes_iodata_bctv7e; ir->gpio_addr = MO_GP0_IO; @@ -215,7 +222,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keydown = 0x02; ir->polling = 5; /* ms */ break; - case CX88_BOARD_PROLINK_PLAYTVPVR: + case CX88_BOARD_PROLINK_PLAYTVPVR: case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: ir_codes = ir_codes_pixelview; ir->gpio_addr = MO_GP1_IO; @@ -419,6 +426,7 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index bc544cc7ccb..f786ab11d2c 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -973,16 +973,32 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, et61x251_show_i2c_val, et61x251_store_i2c_val); -static void et61x251_create_sysfs(struct et61x251_device* cam) +static int et61x251_create_sysfs(struct et61x251_device* cam) { struct video_device *v4ldev = cam->v4ldev; + int rc; - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); + rc = video_device_create_file(v4ldev, &class_device_attr_reg); + if (rc) goto err; + rc = video_device_create_file(v4ldev, &class_device_attr_val); + if (rc) goto err_reg; if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + if (rc) goto err_val; + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); + if (rc) goto err_i2c_reg; } + + return 0; + +err_i2c_reg: + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); +err_val: + video_device_remove_file(v4ldev, &class_device_attr_val); +err_reg: + video_device_remove_file(v4ldev, &class_device_attr_reg); +err: + return rc; } #endif /* CONFIG_VIDEO_ADV_DEBUG */ @@ -2534,7 +2550,9 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; #ifdef CONFIG_VIDEO_ADV_DEBUG - et61x251_create_sysfs(cam); + err = et61x251_create_sysfs(cam); + if (err) + goto fail2; DBG(2, "Optional device control through 'sysfs' interface ready"); #endif @@ -2544,6 +2562,13 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return 0; +#ifdef CONFIG_VIDEO_ADV_DEBUG +fail2: + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); + video_unregister_device(cam->v4ldev); +#endif fail: if (cam) { kfree(cam->control_buffer); diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index ce4886f1528..b4db2cbb5a8 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5648,17 +5648,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf) } static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); -static void ov_create_sysfs(struct video_device *vdev) +static int ov_create_sysfs(struct video_device *vdev) { - video_device_create_file(vdev, &class_device_attr_custom_id); - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_bridge); - video_device_create_file(vdev, &class_device_attr_sensor); - video_device_create_file(vdev, &class_device_attr_brightness); - video_device_create_file(vdev, &class_device_attr_saturation); - video_device_create_file(vdev, &class_device_attr_contrast); - video_device_create_file(vdev, &class_device_attr_hue); - video_device_create_file(vdev, &class_device_attr_exposure); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_custom_id); + if (rc) goto err; + rc = video_device_create_file(vdev, &class_device_attr_model); + if (rc) goto err_id; + rc = video_device_create_file(vdev, &class_device_attr_bridge); + if (rc) goto err_model; + rc = video_device_create_file(vdev, &class_device_attr_sensor); + if (rc) goto err_bridge; + rc = video_device_create_file(vdev, &class_device_attr_brightness); + if (rc) goto err_sensor; + rc = video_device_create_file(vdev, &class_device_attr_saturation); + if (rc) goto err_bright; + rc = video_device_create_file(vdev, &class_device_attr_contrast); + if (rc) goto err_sat; + rc = video_device_create_file(vdev, &class_device_attr_hue); + if (rc) goto err_contrast; + rc = video_device_create_file(vdev, &class_device_attr_exposure); + if (rc) goto err_hue; + + return 0; + +err_hue: + video_device_remove_file(vdev, &class_device_attr_hue); +err_contrast: + video_device_remove_file(vdev, &class_device_attr_contrast); +err_sat: + video_device_remove_file(vdev, &class_device_attr_saturation); +err_bright: + video_device_remove_file(vdev, &class_device_attr_brightness); +err_sensor: + video_device_remove_file(vdev, &class_device_attr_sensor); +err_bridge: + video_device_remove_file(vdev, &class_device_attr_bridge); +err_model: + video_device_remove_file(vdev, &class_device_attr_model); +err_id: + video_device_remove_file(vdev, &class_device_attr_custom_id); +err: + return rc; } /**************************************************************************** @@ -5817,7 +5849,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) ov->vdev->minor); usb_set_intfdata(intf, ov); - ov_create_sysfs(ov->vdev); + if (ov_create_sysfs(ov->vdev)) { + err("ov_create_sysfs failed"); + goto error; + } + return 0; error: diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index df8feac16ae..c80c26be6e4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -221,7 +221,7 @@ static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt, static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt) { int ret; - ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0); + ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL); pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 97e974d9b9c..bb40e908597 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -711,8 +711,8 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) dip->devbase.minor,pvr2_config_get_name(dip->config)); /* Paranoia */ - dip->v4lp = 0; - dip->stream = 0; + dip->v4lp = NULL; + dip->stream = NULL; /* Actual deallocation happens later when all internal references are gone. */ @@ -1076,7 +1076,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL); if (!vp->vdev) { kfree(vp); - return 0; + return NULL; } memset(vp->vdev,0,sizeof(*vp->vdev)); pvr2_channel_init(&vp->channel,mnp); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index c77b85cf3d8..46c11483088 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1024,12 +1024,25 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, NULL); -static void pwc_create_sysfs_files(struct video_device *vdev) +static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_create_file(vdev, &class_device_attr_pan_tilt); - video_device_create_file(vdev, &class_device_attr_button); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_button); + if (rc) + goto err; + if (pdev->features & FEATURE_MOTOR_PANTILT) { + rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + if (rc) goto err_button; + } + + return 0; + +err_button: + video_device_remove_file(vdev, &class_device_attr_button); +err: + return rc; } static void pwc_remove_sysfs_files(struct video_device *vdev) @@ -1408,7 +1421,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id struct usb_device *udev = interface_to_usbdev(intf); struct pwc_device *pdev = NULL; int vendor_id, product_id, type_id; - int i, hint; + int i, hint, rc; int features = 0; int video_nr = -1; /* default: use next available device */ char serial_number[30], *name; @@ -1709,9 +1722,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { PWC_ERROR("Failed to register as video device (%d).\n", i); - video_device_release(pdev->vdev); /* Drip... drip... drip... */ - kfree(pdev); /* Oops, no memory leaks please */ - return -EIO; + rc = i; + goto err; } else { PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); @@ -1723,13 +1735,24 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); usb_set_intfdata (intf, pdev); - pwc_create_sysfs_files(pdev->vdev); + rc = pwc_create_sysfs_files(pdev->vdev); + if (rc) + goto err_unreg; /* Set the leds off */ pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); return 0; + +err_unreg: + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = NULL; + video_unregister_device(pdev->vdev); +err: + video_device_release(pdev->vdev); /* Drip... drip... drip... */ + kfree(pdev); /* Oops, no memory leaks please */ + return rc; } /* The user janked out the cable... */ diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 974179d4d38..c5719f7bd1a 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -960,6 +960,8 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) reg |= 0x10; } else if (std == V4L2_STD_NTSC_M_JP) { reg |= 0x40; + } else if (std == V4L2_STD_SECAM) { + reg |= 0x50; } saa711x_write(client, R_0E_CHROMA_CNTL_1, reg); } else { diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c9d8e3b9cc3..51f0cfdcb68 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2969,7 +2969,7 @@ struct saa7134_board saa7134_boards[] = { /* Petr Baudis <pasky@ucw.cz> */ .name = "AVerMedia TV Hybrid A16AR", .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, /* untested */ + .tuner_type = TUNER_PHILIPS_TD1316, /* untested */ .radio_type = TUNER_TEA5767, /* untested */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -3718,6 +3718,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: + case SAA7134_BOARD_AVERMEDIA_777: /* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ case SAA7134_BOARD_VIDEOMATE_TV_PVR: case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: @@ -3734,6 +3735,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_FLYDVBT_LR301: case SAA7134_BOARD_FLYDVBTDUO: case SAA7134_BOARD_PROTEUS_2309: + case SAA7134_BOARD_AVERMEDIA_A16AR: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -3772,7 +3774,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); break; - case SAA7134_BOARD_AVERMEDIA_A16AR: case SAA7134_BOARD_AVERMEDIA_CARDBUS: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1ba53b525ad..6b61d9b2fcb 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1147,6 +1147,8 @@ static int dvb_init(struct saa7134_dev *dev) &philips_europa_config, &dev->i2c_adap); if (dev->dvb.frontend) { + dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; + dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index ff5991136f4..dee83552e68 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -185,7 +185,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - case SAA7134_BOARD_AVERMEDIA_A16AR: ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; mask_keydown = 0x000010; @@ -194,6 +193,16 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPMODE0, 0x4); saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; + case SAA7134_BOARD_AVERMEDIA_777: + case SAA7134_BOARD_AVERMEDIA_A16AR: + ir_codes = ir_codes_avermedia; + mask_keycode = 0x02F200; + mask_keydown = 0x000400; + polling = 50; // ms + /* Without this we won't receive key up events */ + saa_setb(SAA7134_GPIO_GPMODE1, 0x1); + saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); + break; case SAA7134_BOARD_KWORLD_TERMINATOR: ir_codes = ir_codes_pixelview; mask_keycode = 0x00001f; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 203302f2182..830617ea81c 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2248,7 +2248,11 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, t->type = V4L2_TUNER_RADIO; saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - + if (dev->input->amux == TV) { + t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); + t->rxsubchans = (saa_readb(0x529) & 0x08) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } return 0; } case VIDIOC_S_TUNER: diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 3e0ff8a7846..a4702d3c2ac 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1240,23 +1240,53 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); -static void sn9c102_create_sysfs(struct sn9c102_device* cam) +static int sn9c102_create_sysfs(struct sn9c102_device* cam) { struct video_device *v4ldev = cam->v4ldev; + int rc; + + rc = video_device_create_file(v4ldev, &class_device_attr_reg); + if (rc) goto err; + rc = video_device_create_file(v4ldev, &class_device_attr_val); + if (rc) goto err_reg; + rc = video_device_create_file(v4ldev, &class_device_attr_frame_header); + if (rc) goto err_val; - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_frame_header); - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - video_device_create_file(v4ldev, &class_device_attr_green); - else if (cam->bridge == BRIDGE_SN9C103) { - video_device_create_file(v4ldev, &class_device_attr_blue); - video_device_create_file(v4ldev, &class_device_attr_red); - } if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + if (rc) goto err_frhead; + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); + if (rc) goto err_i2c_reg; + } + + if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { + rc = video_device_create_file(v4ldev, &class_device_attr_green); + if (rc) goto err_i2c_val; + } else if (cam->bridge == BRIDGE_SN9C103) { + rc = video_device_create_file(v4ldev, &class_device_attr_blue); + if (rc) goto err_i2c_val; + rc = video_device_create_file(v4ldev, &class_device_attr_red); + if (rc) goto err_blue; } + + return 0; + +err_blue: + video_device_remove_file(v4ldev, &class_device_attr_blue); +err_i2c_val: + if (cam->sensor.sysfs_ops) + video_device_remove_file(v4ldev, &class_device_attr_i2c_val); +err_i2c_reg: + if (cam->sensor.sysfs_ops) + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); +err_frhead: + video_device_remove_file(v4ldev, &class_device_attr_frame_header); +err_val: + video_device_remove_file(v4ldev, &class_device_attr_val); +err_reg: + video_device_remove_file(v4ldev, &class_device_attr_reg); +err: + return rc; } #endif /* CONFIG_VIDEO_ADV_DEBUG */ @@ -2809,10 +2839,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "V4L2 device registration failed"); if (err == -ENFILE && video_nr[dev_nr] == -1) DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); - goto fail; + goto fail2; } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); @@ -2823,7 +2850,9 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; #ifdef CONFIG_VIDEO_ADV_DEBUG - sn9c102_create_sysfs(cam); + err = sn9c102_create_sysfs(cam); + if (err) + goto fail3; DBG(2, "Optional device control through 'sysfs' interface ready"); #endif @@ -2833,6 +2862,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return 0; +#ifdef CONFIG_VIDEO_ADV_DEBUG +fail3: + video_unregister_device(cam->v4ldev); +#endif +fail2: + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); fail: if (cam) { kfree(cam->control_buffer); diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 87e11300181..6d1ef1e2e8e 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -516,16 +516,45 @@ stv680_file(frames_read, framecount, "%d\n"); stv680_file(packets_dropped, dropped, "%d\n"); stv680_file(decoding_errors, error, "%d\n"); -static void stv680_create_sysfs_files(struct video_device *vdev) +static int stv680_create_sysfs_files(struct video_device *vdev) { - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_in_use); - video_device_create_file(vdev, &class_device_attr_streaming); - video_device_create_file(vdev, &class_device_attr_palette); - video_device_create_file(vdev, &class_device_attr_frames_total); - video_device_create_file(vdev, &class_device_attr_frames_read); - video_device_create_file(vdev, &class_device_attr_packets_dropped); - video_device_create_file(vdev, &class_device_attr_decoding_errors); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_model); + if (rc) goto err; + rc = video_device_create_file(vdev, &class_device_attr_in_use); + if (rc) goto err_model; + rc = video_device_create_file(vdev, &class_device_attr_streaming); + if (rc) goto err_inuse; + rc = video_device_create_file(vdev, &class_device_attr_palette); + if (rc) goto err_stream; + rc = video_device_create_file(vdev, &class_device_attr_frames_total); + if (rc) goto err_pal; + rc = video_device_create_file(vdev, &class_device_attr_frames_read); + if (rc) goto err_framtot; + rc = video_device_create_file(vdev, &class_device_attr_packets_dropped); + if (rc) goto err_framread; + rc = video_device_create_file(vdev, &class_device_attr_decoding_errors); + if (rc) goto err_dropped; + + return 0; + +err_dropped: + video_device_remove_file(vdev, &class_device_attr_packets_dropped); +err_framread: + video_device_remove_file(vdev, &class_device_attr_frames_read); +err_framtot: + video_device_remove_file(vdev, &class_device_attr_frames_total); +err_pal: + video_device_remove_file(vdev, &class_device_attr_palette); +err_stream: + video_device_remove_file(vdev, &class_device_attr_streaming); +err_inuse: + video_device_remove_file(vdev, &class_device_attr_in_use); +err_model: + video_device_remove_file(vdev, &class_device_attr_model); +err: + return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) @@ -1418,9 +1447,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); usb_set_intfdata (intf, stv680); - stv680_create_sysfs_files(stv680->vdev); + retval = stv680_create_sysfs_files(stv680->vdev); + if (retval) + goto error_unreg; return 0; +error_unreg: + video_unregister_device(stv680->vdev); error_vdev: video_device_release(stv680->vdev); error: diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 8fff642fad5..781682373b6 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1046,7 +1046,6 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), - .has_tda9887 = 1, }, }; diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e6baaee038b..6b9ef731b83 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -468,7 +468,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); - if ( (eeprom_data[i + 8] && 0xf0) && + if ( (eeprom_data[i + 8] & 0xf0) && (tvee->serial_number < 0xffffff) ) { tvee->MAC_address[0] = 0x00; tvee->MAC_address[1] = 0x0D; diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 479a0675cf6..d424a4129d6 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -17,10 +17,11 @@ */ #define dbgarg(cmd, fmt, arg...) \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ printk (KERN_DEBUG "%s: ", vfd->name); \ v4l_printk_ioctl(cmd); \ - printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); + printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \ + } #define dbgarg2(fmt, arg...) \ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ @@ -1287,6 +1288,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; + int i; if (!vfd->tvnormsize) { printk (KERN_WARNING "%s: no TV norms defined!\n", @@ -1297,8 +1299,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - v4l2_video_std_construct(&s, vfd->tvnorms[vfd->current_norm].id, - vfd->tvnorms[vfd->current_norm].name); + for (i = 0; i < vfd->tvnormsize; i++) + if (vfd->tvnorms[i].id == vfd->current_norm) + break; + if (i >= vfd->tvnormsize) + return -EINVAL; + + v4l2_video_std_construct(&s, vfd->current_norm, + vfd->tvnorms[i].name); memset(p,0,sizeof(*p)); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index e7c01d560b6..3c8dc72dc8e 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -272,7 +272,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, /* Get first addr pointed to pixel position */ oldpg=get_addr_pos(pos,pages,to_addr); - pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT); + pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; /* We will just duplicate the second pixel at the packet */ @@ -287,7 +287,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, for (color=0;color<4;color++) { pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { - pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT); + pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); kunmap_atomic(basep, KM_BOUNCE_READ); basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset; oldpg=pgpos; @@ -339,8 +339,8 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, for (color=0;color<4;color++) { pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { - pg=pfn_to_page(to_addr[pgpos]. - sg->dma_address + pg=pfn_to_page(sg_dma_address( + to_addr[pgpos].sg) >> PAGE_SHIFT); kunmap_atomic(basep, KM_BOUNCE_READ); @@ -386,7 +386,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) struct timeval ts; /* Test if DMA mapping is ready */ - if (!vb->dma.sglist[0].dma_address) + if (!sg_dma_address(&vb->dma.sglist[0])) return; prep_to_addr(to_addr,vb); @@ -783,7 +783,7 @@ static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, for (i = 0; i < nents; i++ ) { BUG_ON(!sg[i].page); - sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset; + sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset; } return nents; diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index c537d71c18e..a4afad4ecab 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -75,8 +75,8 @@ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.01" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.01" +#define MPT_LINUX_VERSION_COMMON "3.04.02" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.02" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e57bb035a02..1dd49177315 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -96,6 +96,10 @@ static int mptfc_qcmd(struct scsi_cmnd *SCpnt, static void mptfc_target_destroy(struct scsi_target *starget); static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); static void __devexit mptfc_remove(struct pci_dev *pdev); +static int mptfc_abort(struct scsi_cmnd *SCpnt); +static int mptfc_dev_reset(struct scsi_cmnd *SCpnt); +static int mptfc_bus_reset(struct scsi_cmnd *SCpnt); +static int mptfc_host_reset(struct scsi_cmnd *SCpnt); static struct scsi_host_template mptfc_driver_template = { .module = THIS_MODULE, @@ -110,10 +114,10 @@ static struct scsi_host_template mptfc_driver_template = { .target_destroy = mptfc_target_destroy, .slave_destroy = mptscsih_slave_destroy, .change_queue_depth = mptscsih_change_queue_depth, - .eh_abort_handler = mptscsih_abort, - .eh_device_reset_handler = mptscsih_dev_reset, - .eh_bus_reset_handler = mptscsih_bus_reset, - .eh_host_reset_handler = mptscsih_host_reset, + .eh_abort_handler = mptfc_abort, + .eh_device_reset_handler = mptfc_dev_reset, + .eh_bus_reset_handler = mptfc_bus_reset, + .eh_host_reset_handler = mptfc_host_reset, .bios_param = mptscsih_bios_param, .can_queue = MPT_FC_CAN_QUEUE, .this_id = -1, @@ -171,6 +175,77 @@ static struct fc_function_template mptfc_transport_functions = { .show_host_symbolic_name = 1, }; +static int +mptfc_block_error_handler(struct scsi_cmnd *SCpnt, + int (*func)(struct scsi_cmnd *SCpnt), + const char *caller) +{ + struct scsi_device *sdev = SCpnt->device; + struct Scsi_Host *shost = sdev->host; + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + unsigned long flags; + int ready; + + spin_lock_irqsave(shost->host_lock, flags); + while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { + spin_unlock_irqrestore(shost->host_lock, flags); + dfcprintk ((MYIOC_s_INFO_FMT + "mptfc_block_error_handler.%d: %d:%d, port status is " + "DID_IMM_RETRY, deferring %s recovery.\n", + ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun,caller)); + msleep(1000); + spin_lock_irqsave(shost->host_lock, flags); + } + spin_unlock_irqrestore(shost->host_lock, flags); + + if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { + dfcprintk ((MYIOC_s_INFO_FMT + "%s.%d: %d:%d, failing recovery, " + "port state %d, vdev %p.\n", caller, + ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun,ready, + SCpnt->device->hostdata)); + return FAILED; + } + dfcprintk ((MYIOC_s_INFO_FMT + "%s.%d: %d:%d, executing recovery.\n", caller, + ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun)); + return (*func)(SCpnt); +} + +static int +mptfc_abort(struct scsi_cmnd *SCpnt) +{ + return + mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__); +} + +static int +mptfc_dev_reset(struct scsi_cmnd *SCpnt) +{ + return + mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__); +} + +static int +mptfc_bus_reset(struct scsi_cmnd *SCpnt) +{ + return + mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__); +} + +static int +mptfc_host_reset(struct scsi_cmnd *SCpnt) +{ + return + mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__); +} + static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) { @@ -562,6 +637,12 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) return 0; } + if (!SCpnt->device->hostdata) { /* vdev */ + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + /* dd_data is null until finished adding target */ ri = *((struct mptfc_rport_info **)rport->dd_data); if (unlikely(!ri)) { diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c index ac06f10c54e..d96c687aee9 100644 --- a/drivers/message/i2o/bus-osm.c +++ b/drivers/message/i2o/bus-osm.c @@ -80,18 +80,26 @@ static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan); * @dev: device to verify if it is a I2O Bus Adapter device * * Because we want all Bus Adapters always return 0. + * Except when we fail. Then we are sad. * - * Returns 0. + * Returns 0, except when we fail to excel. */ static int i2o_bus_probe(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(get_device(dev)); + int rc; - device_create_file(dev, &dev_attr_scan); + rc = device_create_file(dev, &dev_attr_scan); + if (rc) + goto err_out; osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid); return 0; + +err_out: + put_device(dev); + return rc; }; /** diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 7bd4d85d0b4..a2350640384 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -124,10 +124,10 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait) int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, unsigned long timeout, struct i2o_dma *dma) { - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct i2o_exec_wait *wait; static u32 tcntxt = 0x80000000; - long flags; + unsigned long flags; int rc = 0; wait = i2o_exec_wait_alloc(); @@ -325,13 +325,24 @@ static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL); static int i2o_exec_probe(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(dev); + int rc; - i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + if (rc) goto err_out; - device_create_file(dev, &dev_attr_vendor_id); - device_create_file(dev, &dev_attr_product_id); + rc = device_create_file(dev, &dev_attr_vendor_id); + if (rc) goto err_evtreg; + rc = device_create_file(dev, &dev_attr_product_id); + if (rc) goto err_vid; return 0; + +err_vid: + device_remove_file(dev, &dev_attr_vendor_id); +err_evtreg: + i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); +err_out: + return rc; }; /** diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3df0e7a07c4..00db31c314e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -28,6 +28,18 @@ config IBM_ASM If unsure, say N. +config SGI_IOC4 + tristate "SGI IOC4 Base IO support" + depends on PCI + ---help--- + This option enables basic support for the IOC4 chip on certain + SGI IO controller cards (IO9, IO10, and PCI-RT). This option + does not enable any specific functions on such a card, but provides + necessary infrastructure for other drivers to utilize. + + If you have an SGI Altix with an IOC4-based card say Y. + Otherwise say N. + config TIFM_CORE tristate "TI Flash Media interface support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -57,4 +69,23 @@ config TIFM_7XX1 To compile this driver as a module, choose M here: the module will be called tifm_7xx1. +config MSI_LAPTOP + tristate "MSI Laptop Extras" + depends on X86 + depends on ACPI_EC + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by MSI (MICRO-STAR + INTERNATIONAL): + + MSI MegaBook S270 (MS-1013) + Cytron/TCM/Medion/Tchibo MD96100/SAM2000 + + It adds support for Bluetooth, WLAN and LCD brightness control. + + More information about this driver is available at + <http://0pointer.de/lennart/tchibo.html>. + + If you have an MSI S270 laptop, say Y or M here. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d65ece76095..c9e98ab021c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -5,6 +5,8 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ +obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o +obj-$(CONFIG_SGI_IOC4) += ioc4.o diff --git a/drivers/sn/ioc4.c b/drivers/misc/ioc4.c index 8562821e649..b995a15b752 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/misc/ioc4.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2005-2006 Silicon Graphics, Inc. All Rights Reserved. */ /* This file contains the master driver module for use by SGI IOC4 subdrivers. @@ -29,12 +29,10 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/ioc4.h> -#include <linux/mmtimer.h> -#include <linux/rtc.h> +#include <linux/ktime.h> #include <linux/mutex.h> -#include <asm/sn/addrs.h> -#include <asm/sn/clksupport.h> -#include <asm/sn/shub_mmr.h> +#include <linux/time.h> +#include <asm/io.h> /*************** * Definitions * @@ -43,7 +41,7 @@ /* Tweakable values */ /* PCI bus speed detection/calibration */ -#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */ +#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */ #define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */ #define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */ #define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */ @@ -143,11 +141,11 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) static void ioc4_clock_calibrate(struct ioc4_driver_data *idd) { - extern unsigned long sn_rtc_cycles_per_second; union ioc4_int_out int_out; union ioc4_gpcr gpcr; unsigned int state, last_state = 1; - uint64_t start = 0, end, period; + struct timespec start_ts, end_ts; + uint64_t start, end, period; unsigned int count = 0; /* Enable output */ @@ -175,30 +173,28 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) if (!last_state && state) { count++; if (count == IOC4_CALIBRATE_END) { - end = rtc_time(); + ktime_get_ts(&end_ts); break; } else if (count == IOC4_CALIBRATE_DISCARD) - start = rtc_time(); + ktime_get_ts(&start_ts); } last_state = state; } while (1); /* Calculation rearranged to preserve intermediate precision. * Logically: - * 1. "end - start" gives us number of RTC cycles over all the - * square wave cycles measured. - * 2. Divide by number of square wave cycles to get number of - * RTC cycles per square wave cycle. + * 1. "end - start" gives us the measurement period over all + * the square wave cycles. + * 2. Divide by number of square wave cycles to get the period + * of a square wave cycle. * 3. Divide by 2*(int_out.fields.count+1), which is the formula * by which the IOC4 generates the square wave, to get the - * number of RTC cycles per IOC4 INT_OUT count. - * 4. Divide by sn_rtc_cycles_per_second to get seconds per - * count. - * 5. Multiply by 1E9 to get nanoseconds per count. + * period of an IOC4 INT_OUT count. */ - period = ((end - start) * 1000000000) / - (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1) - * sn_rtc_cycles_per_second); + end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec; + start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec; + period = (end - start) / + (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)); /* Bounds check the result. */ if (period > IOC4_CALIBRATE_LOW_LIMIT || @@ -210,10 +206,12 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR); period = IOC4_CALIBRATE_DEFAULT; } else { + u64 ns = period; + + do_div(ns, IOC4_EXTINT_COUNT_DIVISOR); printk(KERN_DEBUG - "IOC4 %s: PCI clock is %ld ns.\n", - pci_name(idd->idd_pdev), - period / IOC4_EXTINT_COUNT_DIVISOR); + "IOC4 %s: PCI clock is %llu ns.\n", + pci_name(idd->idd_pdev), (unsigned long long)ns); } /* Remember results. We store the extint clock period rather diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index bbdba7b37e1..db9d7df75ae 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -44,12 +44,14 @@ */ #include <linux/kernel.h> +#include <linux/fs.h> #include <linux/module.h> +#include <linux/buffer_head.h> #include <linux/kprobes.h> -#include <linux/kallsyms.h> +#include <linux/list.h> #include <linux/init.h> -#include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/hrtimer.h> #include <scsi/scsi_cmnd.h> #ifdef CONFIG_IDE @@ -116,16 +118,16 @@ static enum ctype cptype = NONE; static int count = DEFAULT_COUNT; module_param(recur_count, int, 0644); -MODULE_PARM_DESC(recur_count, "Recurcion level for the stack overflow test,\ - default is 10"); +MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ + "default is 10"); module_param(cpoint_name, charp, 0644); -MODULE_PARM_DESC(cpoint_name, "Crash Point, where kernel is to be crashed"); -module_param(cpoint_type, charp, 06444); -MODULE_PARM_DESC(cpoint_type, "Crash Point Type, action to be taken on\ - hitting the crash point"); -module_param(cpoint_count, int, 06444); -MODULE_PARM_DESC(cpoint_count, "Crash Point Count, number of times the \ - crash point is to be hit to trigger action"); +MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); +module_param(cpoint_type, charp, 0644); +MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ + "hitting the crash point"); +module_param(cpoint_count, int, 0644); +MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ + "crash point is to be hit to trigger action"); unsigned int jp_do_irq(unsigned int irq) { @@ -155,8 +157,8 @@ void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) struct scan_control; -unsigned long jp_shrink_page_list(struct list_head *page_list, - struct scan_control *sc) +unsigned long jp_shrink_inactive_list(unsigned long max_scan, + struct zone *zone, struct scan_control *sc) { lkdtm_handler(); jprobe_return(); @@ -295,8 +297,8 @@ int lkdtm_module_init(void) lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; break; case MEM_SWAPOUT: - lkdtm.kp.symbol_name = "shrink_page_list"; - lkdtm.entry = (kprobe_opcode_t*) jp_shrink_page_list; + lkdtm.kp.symbol_name = "shrink_inactive_list"; + lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; break; case TIMERADD: lkdtm.kp.symbol_name = "hrtimer_start"; diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c new file mode 100644 index 00000000000..fdb7153f442 --- /dev/null +++ b/drivers/misc/msi-laptop.c @@ -0,0 +1,395 @@ +/*-*-linux-c-*-*/ + +/* + Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + */ + +/* + * msi-laptop.c - MSI S270 laptop support. This laptop is sold under + * various brands, including "Cytron/TCM/Medion/Tchibo MD96100". + * + * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/: + * + * lcd_level - Screen brightness: contains a single integer in the + * range 0..8. (rw) + * + * auto_brightness - Enable automatic brightness control: contains + * either 0 or 1. If set to 1 the hardware adjusts the screen + * brightness automatically when the power cord is + * plugged/unplugged. (rw) + * + * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro) + * + * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1 + * Please note that this file is constantly 0 if no Bluetooth + * hardware is available. (ro) + * + * In addition to these platform device attributes the driver + * registers itself in the Linux backlight control subsystem and is + * available to userspace under /sys/class/backlight/msi-laptop-bl/. + * + * This driver might work on other laptops produced by MSI. If you + * want to try it you can pass force=1 as argument to the module which + * will force it to load even when the DMI data doesn't identify the + * laptop as MSI S270. YMMV. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/dmi.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> +#include <linux/autoconf.h> + +#define MSI_DRIVER_VERSION "0.5" + +#define MSI_LCD_LEVEL_MAX 9 + +#define MSI_EC_COMMAND_WIRELESS 0x10 +#define MSI_EC_COMMAND_LCD_LEVEL 0x11 + +static int force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); + +static int auto_brightness; +module_param(auto_brightness, int, 0); +MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); + +/* Hardware access */ + +static int set_lcd_level(int level) +{ + u8 buf[2]; + + if (level < 0 || level >= MSI_LCD_LEVEL_MAX) + return -EINVAL; + + buf[0] = 0x80; + buf[1] = (u8) (level*31); + + return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0); +} + +static int get_lcd_level(void) +{ + u8 wdata = 0, rdata; + int result; + + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); + if (result < 0) + return result; + + return (int) rdata / 31; +} + +static int get_auto_brightness(void) +{ + u8 wdata = 4, rdata; + int result; + + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); + if (result < 0) + return result; + + return !!(rdata & 8); +} + +static int set_auto_brightness(int enable) +{ + u8 wdata[2], rdata; + int result; + + wdata[0] = 4; + + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1); + if (result < 0) + return result; + + wdata[0] = 0x84; + wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); + + return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0); +} + +static int get_wireless_state(int *wlan, int *bluetooth) +{ + u8 wdata = 0, rdata; + int result; + + result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1); + if (result < 0) + return -1; + + if (wlan) + *wlan = !!(rdata & 8); + + if (bluetooth) + *bluetooth = !!(rdata & 128); + + return 0; +} + +/* Backlight device stuff */ + +static int bl_get_brightness(struct backlight_device *b) +{ + return get_lcd_level(); +} + + +static int bl_update_status(struct backlight_device *b) +{ + return set_lcd_level(b->props->brightness); +} + +static struct backlight_properties msibl_props = { + .owner = THIS_MODULE, + .get_brightness = bl_get_brightness, + .update_status = bl_update_status, + .max_brightness = MSI_LCD_LEVEL_MAX-1, +}; + +static struct backlight_device *msibl_device; + +/* Platform device */ + +static ssize_t show_wlan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret, enabled; + + ret = get_wireless_state(&enabled, NULL); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", enabled); +} + +static ssize_t show_bluetooth(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret, enabled; + + ret = get_wireless_state(NULL, &enabled); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", enabled); +} + +static ssize_t show_lcd_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_lcd_level(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t store_lcd_level(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + int level, ret; + + if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX)) + return -EINVAL; + + ret = set_lcd_level(level); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t show_auto_brightness(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_auto_brightness(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t store_auto_brightness(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + int enable, ret; + + if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1))) + return -EINVAL; + + ret = set_auto_brightness(enable); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); +static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness); +static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); +static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); + +static struct attribute *msipf_attributes[] = { + &dev_attr_lcd_level.attr, + &dev_attr_auto_brightness.attr, + &dev_attr_bluetooth.attr, + &dev_attr_wlan.attr, + NULL +}; + +static struct attribute_group msipf_attribute_group = { + .attrs = msipf_attributes +}; + +static struct platform_driver msipf_driver = { + .driver = { + .name = "msi-laptop-pf", + .owner = THIS_MODULE, + } +}; + +static struct platform_device *msipf_device; + +/* Initialization */ + +static struct dmi_system_id __initdata msi_dmi_table[] = { + { + .ident = "MSI S270", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"), + } + }, + { + .ident = "Medion MD96100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"), + DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"), + } + }, + { } +}; + + +static int __init msi_init(void) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + + if (!force && !dmi_check_system(msi_dmi_table)) + return -ENODEV; + + if (auto_brightness < 0 || auto_brightness > 2) + return -EINVAL; + + /* Register backlight stuff */ + + msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props); + if (IS_ERR(msibl_device)) + return PTR_ERR(msibl_device); + + ret = platform_driver_register(&msipf_driver); + if (ret) + goto fail_backlight; + + /* Register platform stuff */ + + msipf_device = platform_device_alloc("msi-laptop-pf", -1); + if (!msipf_device) { + ret = -ENOMEM; + goto fail_platform_driver; + } + + ret = platform_device_add(msipf_device); + if (ret) + goto fail_platform_device1; + + ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group); + if (ret) + goto fail_platform_device2; + + /* Disable automatic brightness control by default because + * this module was probably loaded to do brightness control in + * software. */ + + if (auto_brightness != 2) + set_auto_brightness(auto_brightness); + + printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); + + return 0; + +fail_platform_device2: + + platform_device_del(msipf_device); + +fail_platform_device1: + + platform_device_put(msipf_device); + +fail_platform_driver: + + platform_driver_unregister(&msipf_driver); + +fail_backlight: + + backlight_device_unregister(msibl_device); + + return ret; +} + +static void __exit msi_cleanup(void) +{ + + sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); + platform_device_unregister(msipf_device); + platform_driver_unregister(&msipf_driver); + backlight_device_unregister(msibl_device); + + /* Enable automatic brightness control again */ + if (auto_brightness != 2) + set_auto_brightness(1); + + printk(KERN_INFO "msi-laptop: driver unloaded.\n"); +} + +module_init(msi_init); +module_exit(msi_cleanup); + +MODULE_AUTHOR("Lennart Poettering"); +MODULE_DESCRIPTION("MSI Laptop Support"); +MODULE_VERSION(MSI_DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ee8863c123e..766bc54406e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -475,7 +475,7 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) if (bit) { bit -= 1; - ocr = 3 << bit; + ocr &= 3 << bit; host->ios.vdd = bit; mmc_set_ios(host); @@ -1178,14 +1178,29 @@ static void mmc_rescan(void *data) { struct mmc_host *host = data; struct list_head *l, *n; + unsigned char power_mode; mmc_claim_host(host); - if (host->ios.power_mode == MMC_POWER_ON) + /* + * Check for removed cards and newly inserted ones. We check for + * removed cards first so we can intelligently re-select the VDD. + */ + power_mode = host->ios.power_mode; + if (power_mode == MMC_POWER_ON) mmc_check_cards(host); mmc_setup(host); + /* + * Some broken cards process CMD1 even in stand-by state. There is + * no reply, but an ILLEGAL_COMMAND error is cached and returned + * after next command. We poll for card status here to clear any + * possibly pending error. + */ + if (power_mode == MMC_POWER_ON) + mmc_check_cards(host); + if (!list_empty(&host->cards)) { /* * (Re-)calculate the fastest clock rate which the diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 2bacff60913..0fdc55b08a6 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -14,6 +14,7 @@ #include <linux/mmc/protocol.h> #include <linux/mmc/host.h> #include <linux/highmem.h> +#include <asm/io.h> #define DRIVER_NAME "tifm_sd" #define DRIVER_VERSION "0.6" diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index baece61169f..41bfcae1fbf 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1479,6 +1479,7 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, * @buf: the data to write * @page: page number to write * @cached: cached programming + * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ab92cc794c6..6e863aa9894 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -486,7 +486,7 @@ config SGI_IOC3_ETH_HW_TX_CSUM config MIPS_SIM_NET tristate "MIPS simulator Network device (EXPERIMENTAL)" - depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL + depends on MIPS_SIM && EXPERIMENTAL help The MIPSNET device is a simple Ethernet network device which is emulated by the MIPS Simulator. @@ -2112,7 +2112,7 @@ config SKGE config SKY2 tristate "SysKonnect Yukon2 support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + depends on PCI select CRC32 ---help--- This driver supports Gigabit Ethernet adapters based on the @@ -2120,8 +2120,8 @@ config SKY2 Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/ 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21 - This driver does not support the original Yukon chipset: a seperate - driver, skge, is provided for Yukon-based adapters. + There is companion driver for the older Marvell Yukon and + Genesis based adapters: skge. To compile this driver as a module, choose M here: the module will be called sky2. This is recommended. @@ -2288,7 +2288,7 @@ config UGETH_TX_ON_DEMOND config UGETH_HAS_GIGA bool - depends on UCC_GETH && MPC836x + depends on UCC_GETH && PPC_MPC836x config MV643XX_ETH tristate "MV-643XX Ethernet support" @@ -2467,7 +2467,7 @@ config ISERIES_VETH config RIONET tristate "RapidIO Ethernet over messaging driver support" - depends on NETDEVICES && RAPIDIO + depends on RAPIDIO config RIONET_TX_SIZE int "Number of outbound queue entries" @@ -2717,6 +2717,7 @@ config PPP_MPPE select CRYPTO select CRYPTO_SHA1 select CRYPTO_ARC4 + select CRYPTO_ECB ---help--- Support for the MPPE Encryption protocol, as employed by the Microsoft Point-to-Point Tunneling Protocol. @@ -2832,7 +2833,7 @@ config NET_FC "SCSI generic support". config SHAPER - tristate "Traffic Shaper (EXPERIMENTAL)" + tristate "Traffic Shaper (OBSOLETE)" depends on EXPERIMENTAL ---help--- The traffic shaper is a virtual network device that allows you to @@ -2841,9 +2842,9 @@ config SHAPER these virtual devices. See <file:Documentation/networking/shaper.txt> for more information. - An alternative to this traffic shaper is the experimental - Class-Based Queuing (CBQ) scheduling support which you get if you - say Y to "QoS and/or fair queuing" above. + An alternative to this traffic shaper are traffic schedulers which + you'll get if you say Y to "QoS and/or fair queuing" in + "Networking options". To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 0dc70c7b794..aa9dd8f1126 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -337,13 +337,16 @@ static void com20020_set_mc_list(struct net_device *dev) } } -#ifdef MODULE - +#if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \ + defined(CONFIG_ARCNET_COM20020_ISA_MODULE) EXPORT_SYMBOL(com20020_check); EXPORT_SYMBOL(com20020_found); +#endif MODULE_LICENSE("GPL"); +#ifdef MODULE + int init_module(void) { BUGLVL(D_NORMAL) printk(VERSION); diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 127561c782f..8ebd68e2af9 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -193,12 +193,9 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) static int ep93xx_rx(struct net_device *dev, int *budget) { struct ep93xx_priv *ep = netdev_priv(dev); - int tail_offset; int rx_done; int processed; - tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr; - rx_done = 0; processed = 0; while (*budget > 0) { @@ -211,36 +208,28 @@ static int ep93xx_rx(struct net_device *dev, int *budget) entry = ep->rx_pointer; rstat = ep->descs->rstat + entry; - if ((void *)rstat - (void *)ep->descs == tail_offset) { + + rstat0 = rstat->rstat0; + rstat1 = rstat->rstat1; + if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) { rx_done = 1; break; } - rstat0 = rstat->rstat0; - rstat1 = rstat->rstat1; rstat->rstat0 = 0; rstat->rstat1 = 0; - if (!(rstat0 & RSTAT0_RFP)) - printk(KERN_CRIT "ep93xx_rx: buffer not done " - " %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_EOF)) printk(KERN_CRIT "ep93xx_rx: not end-of-frame " " %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_EOB)) printk(KERN_CRIT "ep93xx_rx: not end-of-buffer " " %.8x %.8x\n", rstat0, rstat1); - if (!(rstat1 & RSTAT1_RFP)) - printk(KERN_CRIT "ep93xx_rx: buffer1 not done " - " %.8x %.8x\n", rstat0, rstat1); if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) printk(KERN_CRIT "ep93xx_rx: entry mismatch " " %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_RWE)) { - printk(KERN_NOTICE "ep93xx_rx: receive error " - " %.8x %.8x\n", rstat0, rstat1); - ep->stats.rx_errors++; if (rstat0 & RSTAT0_OE) ep->stats.rx_fifo_errors++; @@ -301,13 +290,8 @@ err: static int ep93xx_have_more_rx(struct ep93xx_priv *ep) { - struct ep93xx_rstat *rstat; - int tail_offset; - - rstat = ep->descs->rstat + ep->rx_pointer; - tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr; - - return !((void *)rstat - (void *)ep->descs == tail_offset); + struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer; + return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); } static int ep93xx_poll(struct net_device *dev, int *budget) @@ -347,7 +331,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) struct ep93xx_priv *ep = netdev_priv(dev); int entry; - if (unlikely(skb->len) > MAX_PKT_SIZE) { + if (unlikely(skb->len > MAX_PKT_SIZE)) { ep->stats.tx_dropped++; dev_kfree_skb(skb); return NETDEV_TX_OK; @@ -379,10 +363,8 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) static void ep93xx_tx_complete(struct net_device *dev) { struct ep93xx_priv *ep = netdev_priv(dev); - int tail_offset; int wake; - tail_offset = rdl(ep, REG_TXSTSQCURADD) - ep->descs_dma_addr; wake = 0; spin_lock(&ep->tx_pending_lock); @@ -393,15 +375,13 @@ static void ep93xx_tx_complete(struct net_device *dev) entry = ep->tx_clean_pointer; tstat = ep->descs->tstat + entry; - if ((void *)tstat - (void *)ep->descs == tail_offset) - break; tstat0 = tstat->tstat0; + if (!(tstat0 & TSTAT0_TXFP)) + break; + tstat->tstat0 = 0; - if (!(tstat0 & TSTAT0_TXFP)) - printk(KERN_CRIT "ep93xx_tx_complete: buffer not done " - " %.8x\n", tstat0); if (tstat0 & TSTAT0_FA) printk(KERN_CRIT "ep93xx_tx_complete: frame aborted " " %.8x\n", tstat0); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 4873dc610d2..7db3c8af089 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -102,7 +102,7 @@ static void enable_mac(struct net_device *, int); // externs extern int get_ethernet_addr(char *ethernet_addr); extern void str2eaddr(unsigned char *ea, unsigned char *str); -extern char * __init prom_getcmdline(void); +extern char * prom_getcmdline(void); /* * Theory of operation diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b124eee4eb1..474a4e3438d 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -908,8 +908,9 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id) istat = br32(bp, B44_ISTAT); imask = br32(bp, B44_IMASK); - /* ??? What the fuck is the purpose of the interrupt mask - * ??? register if we have to mask it out by hand anyways? + /* The interrupt mask register controls which interrupt bits + * will actually raise an interrupt to the CPU when set by hw/firmware, + * but doesn't mask off the bits. */ istat &= imask; if (istat) { @@ -1706,14 +1707,15 @@ static void __b44_set_rx_mode(struct net_device *dev) __b44_set_mac_addr(bp); - if (dev->flags & IFF_ALLMULTI) + if ((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > B44_MCAST_TABLE_SIZE)) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); - for (; i < 64; i++) { + for (; i < 64; i++) __b44_cam_write(bp, zero, i); - } + bw32(bp, B44_RXCONFIG, val); val = br32(bp, B44_CAM_CTRL); bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); @@ -2055,7 +2057,7 @@ static int b44_read_eeprom(struct b44 *bp, u8 *data) u16 *ptr = (u16 *) data; for (i = 0; i < 128; i += 2) - ptr[i / 2] = readw(bp->regs + 4096 + i); + ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); return 0; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index e83bc825f6a..32923162179 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1433,7 +1433,7 @@ void bond_alb_monitor(struct bonding *bond) * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->curr_slave_lock); + write_lock_bh(&bond->curr_slave_lock); if (bond_info->primary_is_promisc && (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { @@ -1448,7 +1448,7 @@ void bond_alb_monitor(struct bonding *bond) bond_info->primary_is_promisc = 0; } - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c0bbddae4ec..17a461152d3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4692,6 +4692,8 @@ static int bond_check_params(struct bond_params *params) return 0; } +static struct lock_class_key bonding_netdev_xmit_lock_key; + /* Create a new bond based on the specified name and bonding parameters. * Caller must NOT hold rtnl_lock; we need to release it here before we * set up our sysfs entries. @@ -4727,6 +4729,9 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond if (res < 0) { goto out_bond; } + + lockdep_set_class(&bond_dev->_xmit_lock, &bonding_netdev_xmit_lock_key); + if (newbond) *newbond = bond_dev->priv; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 966b563e42b..a03d781f6d0 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -509,6 +509,8 @@ etrax_ethernet_init(void) * does not share cacheline with any other data (to avoid cache bug) */ RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); + if (!RxDescList[i].skb) + return -ENOMEM; RxDescList[i].descr.ctrl = 0; RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE; RxDescList[i].descr.next = virt_to_phys(&RxDescList[i + 1]); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 27d5d2f0253..19ab3441269 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2039,7 +2039,6 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu) return 0; } -#ifdef CONFIG_PM static int e100_asf(struct nic *nic) { /* ASF can be enabled from eeprom */ @@ -2048,7 +2047,6 @@ static int e100_asf(struct nic *nic) !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); } -#endif static int e100_up(struct nic *nic) { @@ -2715,34 +2713,35 @@ static void __devexit e100_remove(struct pci_dev *pdev) } } +#ifdef CONFIG_PM static int e100_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); +#ifdef CONFIG_E100_NAPI if (netif_running(netdev)) - e100_down(nic); - e100_hw_reset(nic); - netif_device_detach(netdev); + netif_poll_disable(nic->netdev); +#endif + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); -#ifdef CONFIG_PM pci_save_state(pdev); - if (nic->flags & (wol_magic | e100_asf(nic))) -#else - if (nic->flags & (wol_magic)) -#endif - pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); - else - /* disable PME */ - pci_enable_wake(pdev, 0, 0); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pci_set_power_state(pdev, PCI_D3hot); return 0; } -#ifdef CONFIG_PM static int e100_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -2764,7 +2763,26 @@ static int e100_resume(struct pci_dev *pdev) static void e100_shutdown(struct pci_dev *pdev) { - e100_suspend(pdev, PMSG_SUSPEND); + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + +#ifdef CONFIG_E100_NAPI + if (netif_running(netdev)) + netif_poll_disable(nic->netdev); +#endif + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); } /* ------------------ PCI Error Recovery infrastructure -------------- */ @@ -2848,9 +2866,9 @@ static struct pci_driver e100_driver = { .id_table = e100_id_table, .probe = e100_probe, .remove = __devexit_p(e100_remove), +#ifdef CONFIG_PM /* Power Management hooks */ .suspend = e100_suspend, -#ifdef CONFIG_PM .resume = e100_resume, #endif .shutdown = e100_shutdown, diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 773821e4cf5..c564adbd669 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -461,7 +461,8 @@ e1000_get_regs(struct net_device *netdev, regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ if (hw->mac_type >= e1000_82540 && - hw->media_type == e1000_media_type_copper) { + hw->mac_type < e1000_82571 && + hw->media_type == e1000_media_type_copper) { regs_buff[26] = E1000_READ_REG(hw, MANC); } } @@ -1690,6 +1691,7 @@ static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wol int retval = 1; /* fail by default */ switch (hw->device_id) { + case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 112447fd8bf..449a60303e0 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1961,9 +1961,9 @@ struct e1000_hw { #define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */ /* Transmit Descriptor Control */ -#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */ -#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */ -#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */ +#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ #define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ #define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ce0d35fe394..726ec5e88ab 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -35,7 +35,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "7.2.9-k2"DRIVERNAPI +#define DRV_VERSION "7.2.9-k4"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -699,7 +699,10 @@ e1000_reset(struct e1000_adapter *adapter) phy_data); } - if ((adapter->en_mng_pt) && (adapter->hw.mac_type < e1000_82571)) { + if ((adapter->en_mng_pt) && + (adapter->hw.mac_type >= e1000_82540) && + (adapter->hw.mac_type < e1000_82571) && + (adapter->hw.media_type == e1000_media_type_copper)) { manc = E1000_READ_REG(&adapter->hw, MANC); manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); E1000_WRITE_REG(&adapter->hw, MANC, manc); @@ -1076,8 +1079,9 @@ e1000_remove(struct pci_dev *pdev) flush_scheduled_work(); - if (adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { + if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type < e1000_82571 && + adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); if (manc & E1000_MANC_SMBUS_EN) { manc |= E1000_MANC_ARP_EN; @@ -1804,9 +1808,11 @@ e1000_setup_rctl(struct e1000_adapter *adapter) * followed by the page buffers. Therefore, skb->data is * sized to hold the largest protocol header. */ + /* allocations using alloc_page take too long for regular MTU + * so only enable packet split for jumbo frames */ pages = PAGE_USE_COUNT(adapter->netdev->mtu); - if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) && - PAGE_SIZE <= 16384) + if ((adapter->hw.mac_type >= e1000_82571) && (pages <= 3) && + PAGE_SIZE <= 16384 && (rctl & E1000_RCTL_LPE)) adapter->rx_ps_pages = pages; else adapter->rx_ps_pages = 0; @@ -2986,6 +2992,11 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } + /* 82571 and newer doesn't need the workaround that limited descriptor + * length to 4kB */ + if (adapter->hw.mac_type >= e1000_82571) + max_per_txd = 8192; + #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->gso_size; /* The controller does a simple calculation to @@ -3775,9 +3786,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, length = le16_to_cpu(rx_desc->length); - /* adjust length to remove Ethernet CRC */ - length -= 4; - if (unlikely(!(status & E1000_RXD_STAT_EOP))) { /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" @@ -3805,6 +3813,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, } } + /* adjust length to remove Ethernet CRC, this must be + * done after the TBI_ACCEPT workaround above */ + length -= 4; + /* code added for copybreak, this should improve * performance for small packets with large amounts * of reassembly being done in the stack */ @@ -4773,8 +4785,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } - if (adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { + if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type < e1000_82571 && + adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); if (manc & E1000_MANC_SMBUS_EN) { manc |= E1000_MANC_ARP_EN; @@ -4787,6 +4800,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) if (adapter->hw.phy_type == e1000_phy_igp_3) e1000_phy_powerdown_workaround(&adapter->hw); + if (netif_running(netdev)) + e1000_free_irq(adapter); + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); @@ -4817,6 +4833,10 @@ e1000_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + if (netif_running(netdev) && (err = e1000_request_irq(adapter))) + return err; + + e1000_power_up_phy(adapter); e1000_reset(adapter); E1000_WRITE_REG(&adapter->hw, WUS, ~0); @@ -4825,8 +4845,9 @@ e1000_resume(struct pci_dev *pdev) netif_device_attach(netdev); - if (adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { + if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type < e1000_82571 && + adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(&adapter->hw, MANC, manc); @@ -4914,10 +4935,6 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); - /* Perform card reset only on one instance of the card */ - if (PCI_FUNC (pdev->devfn) != 0) - return PCI_ERS_RESULT_RECOVERED; - e1000_reset(adapter); E1000_WRITE_REG(&adapter->hw, WUS, ~0); @@ -4948,6 +4965,7 @@ static void e1000_io_resume(struct pci_dev *pdev) netif_device_attach(netdev); if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type < e1000_82571 && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); manc &= ~(E1000_MANC_ARP_EN); diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 23b451a8ae1..39ad9f73d1e 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0028" +#define DRV_VERSION "EHEA_0043" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) @@ -50,6 +50,7 @@ #define EHEA_MAX_ENTRIES_SQ 32767 #define EHEA_MIN_ENTRIES_QP 127 +#define EHEA_SMALL_QUEUES #define EHEA_NUM_TX_QP 1 #ifdef EHEA_SMALL_QUEUES @@ -59,11 +60,11 @@ #define EHEA_DEF_ENTRIES_RQ2 1023 #define EHEA_DEF_ENTRIES_RQ3 1023 #else -#define EHEA_MAX_CQE_COUNT 32000 -#define EHEA_DEF_ENTRIES_SQ 16000 -#define EHEA_DEF_ENTRIES_RQ1 32080 -#define EHEA_DEF_ENTRIES_RQ2 4020 -#define EHEA_DEF_ENTRIES_RQ3 4020 +#define EHEA_MAX_CQE_COUNT 4080 +#define EHEA_DEF_ENTRIES_SQ 4080 +#define EHEA_DEF_ENTRIES_RQ1 8160 +#define EHEA_DEF_ENTRIES_RQ2 2040 +#define EHEA_DEF_ENTRIES_RQ3 2040 #endif #define EHEA_MAX_ENTRIES_EQ 20 @@ -104,9 +105,6 @@ #define EHEA_BCMC_VLANID_ALL 0x01 #define EHEA_BCMC_VLANID_SINGLE 0x00 -/* Use this define to kmallocate pHYP control blocks */ -#define H_CB_ALIGNMENT 4096 - #define EHEA_CACHE_LINE 128 /* Memory Regions */ diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 82eb2fb8c75..9f57c2e78ce 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -238,7 +238,7 @@ static void ehea_get_ethtool_stats(struct net_device *dev, data[i++] = port->port_res[0].swqe_refill_th; data[i++] = port->resets; - cb6 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb6) { ehea_error("no mem for cb6"); return; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index c6b31775e26..6ad69610141 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -92,7 +92,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev) memset(stats, 0, sizeof(*stats)); - cb2 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb2) { ehea_error("no mem for cb2"); goto out; @@ -586,8 +586,8 @@ int ehea_sense_port_attr(struct ehea_port *port) u64 hret; struct hcp_ehea_port_cb0 *cb0; - cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); - if (!cb0) { + cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC); /* May be called via */ + if (!cb0) { /* ehea_neq_tasklet() */ ehea_error("no mem for cb0"); ret = -ENOMEM; goto out; @@ -670,7 +670,7 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed) u64 hret; int ret = 0; - cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb4) { ehea_error("no mem for cb4"); ret = -ENOMEM; @@ -765,8 +765,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) { if (!netif_carrier_ok(port->netdev)) { - ret = ehea_sense_port_attr( - adapter->port[portnum]); + ret = ehea_sense_port_attr(port); if (ret) { ehea_error("failed resensing port " "attributes"); @@ -818,7 +817,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) netif_stop_queue(port->netdev); break; default: - ehea_error("unknown event code %x", ec); + ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe); break; } } @@ -986,7 +985,7 @@ static int ehea_configure_port(struct ehea_port *port) struct hcp_ehea_port_cb0 *cb0; ret = -ENOMEM; - cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb0) goto out; @@ -1444,7 +1443,7 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa) goto out; } - cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb0) { ehea_error("no mem for cb0"); ret = -ENOMEM; @@ -1502,7 +1501,7 @@ static void ehea_promiscuous(struct net_device *dev, int enable) if ((enable && port->promisc) || (!enable && !port->promisc)) return; - cb7 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb7 = kzalloc(PAGE_SIZE, GFP_ATOMIC); if (!cb7) { ehea_error("no mem for cb7"); goto out; @@ -1606,7 +1605,7 @@ static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr) struct ehea_mc_list *ehea_mcl_entry; u64 hret; - ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_KERNEL); + ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC); if (!ehea_mcl_entry) { ehea_error("no mem for mcl_entry"); return; @@ -1841,7 +1840,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) if (netif_msg_tx_queued(port)) { ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr); - ehea_dump(swqe, sizeof(*swqe), "swqe"); + ehea_dump(swqe, 512, "swqe"); } ehea_post_swqe(pr->qp, swqe); @@ -1871,7 +1870,7 @@ static void ehea_vlan_rx_register(struct net_device *dev, port->vgrp = grp; - cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb1) { ehea_error("no mem for cb1"); goto out; @@ -1900,7 +1899,7 @@ static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) int index; u64 hret; - cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb1) { ehea_error("no mem for cb1"); goto out; @@ -1936,7 +1935,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (port->vgrp) port->vgrp->vlan_devices[vid] = NULL; - cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb1) { ehea_error("no mem for cb1"); goto out; @@ -1969,7 +1968,7 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp) u64 dummy64 = 0; struct hcp_modify_qp_cb0* cb0; - cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb0) { ret = -ENOMEM; goto out; @@ -2270,7 +2269,7 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) u64 hret; int ret; - cb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb) { ret = -ENOMEM; goto out; @@ -2341,7 +2340,7 @@ static int ehea_setup_single_port(struct ehea_port *port, goto out; /* Enable Jumbo frames */ - cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); + cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb4) { ehea_error("no mem for cb4"); } else { diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 4a85aca4c7e..0cfc2bc1a27 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -44,71 +44,99 @@ static inline u16 get_order_of_qentries(u16 queue_entries) #define H_ALL_RES_TYPE_MR 5 #define H_ALL_RES_TYPE_MW 6 -static long ehea_hcall_9arg_9ret(unsigned long opcode, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5, unsigned long arg6, - unsigned long arg7, unsigned long arg8, - unsigned long arg9, unsigned long *out1, - unsigned long *out2,unsigned long *out3, - unsigned long *out4,unsigned long *out5, - unsigned long *out6,unsigned long *out7, - unsigned long *out8,unsigned long *out9) +static long ehea_plpar_hcall_norets(unsigned long opcode, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6, + unsigned long arg7) { - long hret; + long ret; int i, sleep_msecs; for (i = 0; i < 5; i++) { - hret = plpar_hcall_9arg_9ret(opcode,arg1, arg2, arg3, arg4, - arg5, arg6, arg7, arg8, arg9, out1, - out2, out3, out4, out5, out6, out7, - out8, out9); - if (H_IS_LONG_BUSY(hret)) { - sleep_msecs = get_longbusy_msecs(hret); + ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, + arg5, arg6, arg7); + + if (H_IS_LONG_BUSY(ret)) { + sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); continue; } - if (hret < H_SUCCESS) - ehea_error("op=%lx hret=%lx " - "i1=%lx i2=%lx i3=%lx i4=%lx i5=%lx i6=%lx " - "i7=%lx i8=%lx i9=%lx " - "o1=%lx o2=%lx o3=%lx o4=%lx o5=%lx o6=%lx " - "o7=%lx o8=%lx o9=%lx", - opcode, hret, arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8, arg9, *out1, *out2, *out3, - *out4, *out5, *out6, *out7, *out8, *out9); - return hret; + if (ret < H_SUCCESS) + ehea_error("opcode=%lx ret=%lx" + " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" + " arg5=%lx arg6=%lx arg7=%lx ", + opcode, ret, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7); + + return ret; } + return H_BUSY; } -u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, - const u64 qp_handle, const u64 sel_mask, void *cb_addr) +static long ehea_plpar_hcall9(unsigned long opcode, + unsigned long *outs, /* array of 9 outputs */ + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6, + unsigned long arg7, + unsigned long arg8, + unsigned long arg9) { - u64 dummy; + long ret; + int i, sleep_msecs; - if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) { - ehea_error("not on pageboundary"); - return H_PARAMETER; + for (i = 0; i < 5; i++) { + ret = plpar_hcall9(opcode, outs, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9); + + if (H_IS_LONG_BUSY(ret)) { + sleep_msecs = get_longbusy_msecs(ret); + msleep_interruptible(sleep_msecs); + continue; + } + + if (ret < H_SUCCESS) + ehea_error("opcode=%lx ret=%lx" + " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" + " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" + " arg9=%lx" + " out1=%lx out2=%lx out3=%lx out4=%lx" + " out5=%lx out6=%lx out7=%lx out8=%lx" + " out9=%lx", + opcode, ret, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9, + outs[0], outs[1], outs[2], outs[3], + outs[4], outs[5], outs[6], outs[7], + outs[8]); + + return ret; } - return ehea_hcall_9arg_9ret(H_QUERY_HEA_QP, - adapter_handle, /* R4 */ - qp_category, /* R5 */ - qp_handle, /* R6 */ - sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return H_BUSY; +} + +u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, + const u64 qp_handle, const u64 sel_mask, void *cb_addr) +{ + return ehea_plpar_hcall_norets(H_QUERY_HEA_QP, + adapter_handle, /* R4 */ + qp_category, /* R5 */ + qp_handle, /* R6 */ + sel_mask, /* R7 */ + virt_to_abs(cb_addr), /* R8 */ + 0, 0); } /* input param R5 */ @@ -180,6 +208,7 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, u64 *qp_handle, struct h_epas *h_epas) { u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; u64 allocate_controls = EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0) @@ -219,45 +248,29 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold) | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold); - u64 r5_out = 0; - u64 r6_out = 0; - u64 r7_out = 0; - u64 r8_out = 0; - u64 r9_out = 0; - u64 g_la_user_out = 0; - u64 r11_out = 0; - u64 r12_out = 0; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - allocate_controls, /* R5 */ - init_attr->send_cq_handle, /* R6 */ - init_attr->recv_cq_handle, /* R7 */ - init_attr->aff_eq_handle, /* R8 */ - r9_reg, /* R9 */ - max_r10_reg, /* R10 */ - r11_in, /* R11 */ - threshold, /* R12 */ - qp_handle, /* R4 */ - &r5_out, /* R5 */ - &r6_out, /* R6 */ - &r7_out, /* R7 */ - &r8_out, /* R8 */ - &r9_out, /* R9 */ - &g_la_user_out, /* R10 */ - &r11_out, /* R11 */ - &r12_out); /* R12 */ - - init_attr->qp_nr = (u32)r5_out; + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + allocate_controls, /* R5 */ + init_attr->send_cq_handle, /* R6 */ + init_attr->recv_cq_handle, /* R7 */ + init_attr->aff_eq_handle, /* R8 */ + r9_reg, /* R9 */ + max_r10_reg, /* R10 */ + r11_in, /* R11 */ + threshold); /* R12 */ + + *qp_handle = outs[0]; + init_attr->qp_nr = (u32)outs[1]; init_attr->act_nr_send_wqes = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, outs[2]); init_attr->act_nr_rwqes_rq1 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, outs[2]); init_attr->act_nr_rwqes_rq2 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, outs[2]); init_attr->act_nr_rwqes_rq3 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, outs[2]); init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq; init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1; @@ -265,25 +278,25 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3; init_attr->nr_sq_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, outs[4]); init_attr->nr_rq1_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, outs[4]); init_attr->nr_rq2_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, outs[5]); init_attr->nr_rq3_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, outs[5]); init_attr->liobn_sq = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, outs[7]); init_attr->liobn_rq1 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, outs[7]); init_attr->liobn_rq2 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, outs[8]); init_attr->liobn_rq3 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, outs[8]); if (!hret) - hcp_epas_ctor(h_epas, g_la_user_out, g_la_user_out); + hcp_epas_ctor(h_epas, outs[6], outs[6]); return hret; } @@ -292,31 +305,24 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, struct ehea_cq_attr *cq_attr, u64 *cq_handle, struct h_epas *epas) { - u64 hret, dummy, act_nr_of_cqes_out, act_pages_out; - u64 g_la_privileged_out, g_la_user_out; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - H_ALL_RES_TYPE_CQ, /* R5 */ - cq_attr->eq_handle, /* R6 */ - cq_attr->cq_token, /* R7 */ - cq_attr->max_nr_of_cqes, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - cq_handle, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &act_nr_of_cqes_out, /* R7 */ - &act_pages_out, /* R8 */ - &g_la_privileged_out, /* R9 */ - &g_la_user_out, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - - cq_attr->act_nr_of_cqes = act_nr_of_cqes_out; - cq_attr->nr_pages = act_pages_out; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + H_ALL_RES_TYPE_CQ, /* R5 */ + cq_attr->eq_handle, /* R6 */ + cq_attr->cq_token, /* R7 */ + cq_attr->max_nr_of_cqes, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + *cq_handle = outs[0]; + cq_attr->act_nr_of_cqes = outs[3]; + cq_attr->nr_pages = outs[4]; if (!hret) - hcp_epas_ctor(epas, g_la_privileged_out, g_la_user_out); + hcp_epas_ctor(epas, outs[5], outs[6]); return hret; } @@ -361,9 +367,8 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, struct ehea_eq_attr *eq_attr, u64 *eq_handle) { - u64 hret, dummy, eq_liobn, allocate_controls; - u64 ist1_out, ist2_out, ist3_out, ist4_out; - u64 act_nr_of_eqes_out, act_pages_out; + u64 hret, allocate_controls; + u64 outs[PLPAR_HCALL9_BUFSIZE]; /* resource type */ allocate_controls = @@ -372,27 +377,20 @@ u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen) | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1); - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - allocate_controls, /* R5 */ - eq_attr->max_nr_of_eqes, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R10 */ - eq_handle, /* R4 */ - &dummy, /* R5 */ - &eq_liobn, /* R6 */ - &act_nr_of_eqes_out, /* R7 */ - &act_pages_out, /* R8 */ - &ist1_out, /* R9 */ - &ist2_out, /* R10 */ - &ist3_out, /* R11 */ - &ist4_out); /* R12 */ - - eq_attr->act_nr_of_eqes = act_nr_of_eqes_out; - eq_attr->nr_pages = act_pages_out; - eq_attr->ist1 = ist1_out; - eq_attr->ist2 = ist2_out; - eq_attr->ist3 = ist3_out; - eq_attr->ist4 = ist4_out; + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + allocate_controls, /* R5 */ + eq_attr->max_nr_of_eqes, /* R6 */ + 0, 0, 0, 0, 0, 0); /* R7-R10 */ + + *eq_handle = outs[0]; + eq_attr->act_nr_of_eqes = outs[3]; + eq_attr->nr_pages = outs[4]; + eq_attr->ist1 = outs[5]; + eq_attr->ist2 = outs[6]; + eq_attr->ist3 = outs[7]; + eq_attr->ist4 = outs[8]; return hret; } @@ -402,31 +400,22 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat, void *cb_addr, u64 *inv_attr_id, u64 *proc_mask, u16 *out_swr, u16 *out_rwr) { - u64 hret, dummy, act_out_swr, act_out_rwr; - - if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) { - ehea_error("not on page boundary"); - return H_PARAMETER; - } - - hret = ehea_hcall_9arg_9ret(H_MODIFY_HEA_QP, - adapter_handle, /* R4 */ - (u64) cat, /* R5 */ - qp_handle, /* R6 */ - sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - inv_attr_id, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &act_out_swr, /* R7 */ - &act_out_rwr, /* R8 */ - proc_mask, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - *out_swr = act_out_swr; - *out_rwr = act_out_rwr; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP, + outs, + adapter_handle, /* R4 */ + (u64) cat, /* R5 */ + qp_handle, /* R6 */ + sel_mask, /* R7 */ + virt_to_abs(cb_addr), /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + *inv_attr_id = outs[0]; + *out_swr = outs[3]; + *out_rwr = outs[4]; + *proc_mask = outs[5]; return hret; } @@ -435,122 +424,81 @@ u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize, const u8 queue_type, const u64 resource_handle, const u64 log_pageaddr, u64 count) { - u64 dummy, reg_control; + u64 reg_control; reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize) | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type); - return ehea_hcall_9arg_9ret(H_REGISTER_HEA_RPAGES, - adapter_handle, /* R4 */ - reg_control, /* R5 */ - resource_handle, /* R6 */ - log_pageaddr, /* R7 */ - count, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_REGISTER_HEA_RPAGES, + adapter_handle, /* R4 */ + reg_control, /* R5 */ + resource_handle, /* R6 */ + log_pageaddr, /* R7 */ + count, /* R8 */ + 0, 0); /* R9-R10 */ } u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle, const u64 vaddr_in, const u32 access_ctrl, const u32 pd, struct ehea_mr *mr) { - u64 hret, dummy, lkey_out; - - hret = ehea_hcall_9arg_9ret(H_REGISTER_SMR, - adapter_handle , /* R4 */ - orig_mr_handle, /* R5 */ - vaddr_in, /* R6 */ - (((u64)access_ctrl) << 32ULL), /* R7 */ - pd, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &mr->handle, /* R4 */ - &dummy, /* R5 */ - &lkey_out, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - mr->lkey = (u32)lkey_out; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_REGISTER_SMR, + outs, + adapter_handle , /* R4 */ + orig_mr_handle, /* R5 */ + vaddr_in, /* R6 */ + (((u64)access_ctrl) << 32ULL), /* R7 */ + pd, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + mr->handle = outs[0]; + mr->lkey = (u32)outs[2]; return hret; } u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle) { - u64 hret, dummy, ladr_next_sq_wqe_out; - u64 ladr_next_rq1_wqe_out, ladr_next_rq2_wqe_out, ladr_next_rq3_wqe_out; - - hret = ehea_hcall_9arg_9ret(H_DISABLE_AND_GET_HEA, - adapter_handle, /* R4 */ - H_DISABLE_GET_EHEA_WQE_P, /* R5 */ - qp_handle, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R12 */ - &ladr_next_sq_wqe_out, /* R4 */ - &ladr_next_rq1_wqe_out, /* R5 */ - &ladr_next_rq2_wqe_out, /* R6 */ - &ladr_next_rq3_wqe_out, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - return hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA, + outs, + adapter_handle, /* R4 */ + H_DISABLE_GET_EHEA_WQE_P, /* R5 */ + qp_handle, /* R6 */ + 0, 0, 0, 0, 0, 0); /* R7-R12 */ } u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle) { - u64 dummy; - - return ehea_hcall_9arg_9ret(H_FREE_RESOURCE, - adapter_handle, /* R4 */ - res_handle, /* R5 */ - 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_FREE_RESOURCE, + adapter_handle, /* R4 */ + res_handle, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ } u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, const u64 length, const u32 access_ctrl, const u32 pd, u64 *mr_handle, u32 *lkey) { - u64 hret, dummy, lkey_out; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - 5, /* R5 */ - vaddr, /* R6 */ - length, /* R7 */ - (((u64) access_ctrl) << 32ULL),/* R8 */ - pd, /* R9 */ - 0, 0, 0, /* R10-R12 */ - mr_handle, /* R4 */ - &dummy, /* R5 */ - &lkey_out, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - *lkey = (u32) lkey_out; - + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + 5, /* R5 */ + vaddr, /* R6 */ + length, /* R7 */ + (((u64) access_ctrl) << 32ULL), /* R8 */ + pd, /* R9 */ + 0, 0, 0); /* R10-R12 */ + + *mr_handle = outs[0]; + *lkey = (u32)outs[2]; return hret; } @@ -558,7 +506,7 @@ u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle, const u8 pagesize, const u8 queue_type, const u64 log_pageaddr, const u64 count) { - if ((count > 1) && (log_pageaddr & 0xfff)) { + if ((count > 1) && (log_pageaddr & ~PAGE_MASK)) { ehea_error("not on pageboundary"); return H_PARAMETER; } @@ -570,23 +518,14 @@ u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle, u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr) { - u64 hret, dummy, cb_logaddr; + u64 hret, cb_logaddr; cb_logaddr = virt_to_abs(cb_addr); - hret = ehea_hcall_9arg_9ret(H_QUERY_HEA, - adapter_handle, /* R4 */ - cb_logaddr, /* R5 */ - 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + hret = ehea_plpar_hcall_norets(H_QUERY_HEA, + adapter_handle, /* R4 */ + cb_logaddr, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ #ifdef DEBUG ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); #endif @@ -597,36 +536,28 @@ u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 port_info, dummy; + u64 port_info; u64 cb_logaddr = virt_to_abs(cb_addr); u64 arr_index = 0; port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat) | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num); - return ehea_hcall_9arg_9ret(H_QUERY_HEA_PORT, - adapter_handle, /* R4 */ - port_info, /* R5 */ - select_mask, /* R6 */ - arr_index, /* R7 */ - cb_logaddr, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_QUERY_HEA_PORT, + adapter_handle, /* R4 */ + port_info, /* R5 */ + select_mask, /* R6 */ + arr_index, /* R7 */ + cb_logaddr, /* R8 */ + 0, 0); /* R9-R10 */ } u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 port_info, dummy, inv_attr_ident, proc_mask; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + u64 port_info; u64 arr_index = 0; u64 cb_logaddr = virt_to_abs(cb_addr); @@ -635,29 +566,21 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, #ifdef DEBUG ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL"); #endif - return ehea_hcall_9arg_9ret(H_MODIFY_HEA_PORT, - adapter_handle, /* R4 */ - port_info, /* R5 */ - select_mask, /* R6 */ - arr_index, /* R7 */ - cb_logaddr, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &inv_attr_ident, /* R4 */ - &proc_mask, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall9(H_MODIFY_HEA_PORT, + outs, + adapter_handle, /* R4 */ + port_info, /* R5 */ + select_mask, /* R6 */ + arr_index, /* R7 */ + cb_logaddr, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ } u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, const u8 reg_type, const u64 mc_mac_addr, const u16 vlan_id, const u32 hcall_id) { - u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id, dummy; + u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id; u64 mac_addr = mc_mac_addr >> 16; r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num); @@ -665,41 +588,21 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr); r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id); - return ehea_hcall_9arg_9ret(hcall_id, - adapter_handle, /* R4 */ - r5_port_num, /* R5 */ - r6_reg_type, /* R6 */ - r7_mc_mac_addr, /* R7 */ - r8_vlan_id, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(hcall_id, + adapter_handle, /* R4 */ + r5_port_num, /* R5 */ + r6_reg_type, /* R6 */ + r7_mc_mac_addr, /* R7 */ + r8_vlan_id, /* R8 */ + 0, 0); /* R9-R12 */ } u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, const u64 event_mask) { - u64 dummy; - - return ehea_hcall_9arg_9ret(H_RESET_EVENTS, - adapter_handle, /* R4 */ - neq_handle, /* R5 */ - event_mask, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_RESET_EVENTS, + adapter_handle, /* R4 */ + neq_handle, /* R5 */ + event_mask, /* R6 */ + 0, 0, 0, 0); /* R7-R12 */ } diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index fa51e3b5bb0..919f94b7593 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h @@ -81,14 +81,16 @@ static inline u32 get_longbusy_msecs(int long_busy_ret_code) static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel, u64 paddr_user) { - epas->kernel.addr = ioremap(paddr_kernel, PAGE_SIZE); + /* To support 64k pages we must round to 64k page boundary */ + epas->kernel.addr = ioremap((paddr_kernel & PAGE_MASK), PAGE_SIZE) + + (paddr_kernel & ~PAGE_MASK); epas->user.addr = paddr_user; } static inline void hcp_epas_dtor(struct h_epas *epas) { if (epas->kernel.addr) - iounmap(epas->kernel.addr); + iounmap((void __iomem*)((u64)epas->kernel.addr & PAGE_MASK)); epas->user.addr = 0; epas->kernel.addr = 0; diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 3e1862326c8..72ef7bde334 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -209,11 +209,11 @@ int ehea_destroy_cq(struct ehea_cq *cq) { u64 adapter_handle, hret; - adapter_handle = cq->adapter->handle; - if (!cq) return 0; + adapter_handle = cq->adapter->handle; + /* deregister all previous registered pages */ hret = ehea_h_free_resource(adapter_handle, cq->fw_handle); if (hret != H_SUCCESS) { @@ -512,7 +512,7 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter) start = KERNELBASE; end = (u64)high_memory; - nr_pages = (end - start) / PAGE_SIZE; + nr_pages = (end - start) / EHEA_PAGESIZE; pt = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!pt) { @@ -538,9 +538,9 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter) if (nr_pages > 1) { u64 num_pages = min(nr_pages, (u64)512); for (i = 0; i < num_pages; i++) - pt[i] = virt_to_abs((void*)(((u64)start) - + ((k++) * - PAGE_SIZE))); + pt[i] = virt_to_abs((void*)(((u64)start) + + ((k++) * + EHEA_PAGESIZE))); hret = ehea_h_register_rpage_mr(adapter->handle, adapter->mr.handle, 0, @@ -548,8 +548,9 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter) num_pages); nr_pages -= num_pages; } else { - u64 abs_adr = virt_to_abs((void*)(((u64)start) - + (k * PAGE_SIZE))); + u64 abs_adr = virt_to_abs((void*)(((u64)start) + + (k * EHEA_PAGESIZE))); + hret = ehea_h_register_rpage_mr(adapter->handle, adapter->mr.handle, 0, 0, abs_adr,1); diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 8cc3c331aca..b7b8bc2a630 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -162,9 +162,9 @@ static char *version = #include <linux/skbuff.h> #include <linux/bitops.h> #include <linux/jiffies.h> +#include <linux/io.h> #include <asm/system.h> -#include <asm/io.h> #include <asm/dma.h> diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 99b7a411db2..c5ed635bce3 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2497,6 +2497,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name); @@ -2508,16 +2509,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) if (!(events & np->irqmask)) break; - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_tx_done(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); if (events & (NVREG_IRQ_TX_ERR)) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2527,7 +2528,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } @@ -2601,6 +2602,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name); @@ -2614,14 +2616,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) nv_rx_process(dev, dev->weight); if (nv_alloc_rx(dev)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2631,7 +2633,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } } @@ -2648,6 +2650,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name); @@ -2660,14 +2663,14 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) break; if (events & NVREG_IRQ_LINK) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_linkchange(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); np->link_timeout = jiffies + LINK_TIMEOUT; } if (events & (NVREG_IRQ_UNKNOWN)) { @@ -2675,7 +2678,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) dev->name, events); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); pci_push(base); @@ -2685,7 +2688,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4bac3cd8f23..44c9f993dcc 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -212,7 +212,8 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc break; } - free_index = pool->consumer_index++ % pool->size; + free_index = pool->consumer_index; + pool->consumer_index = (pool->consumer_index + 1) % pool->size; index = pool->free_map[free_index]; ibmveth_assert(index != IBM_VETH_INVALID_MAP); @@ -238,7 +239,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc if(lpar_rc != H_SUCCESS) { pool->free_map[free_index] = index; pool->skbuff[index] = NULL; - pool->consumer_index--; + if (pool->consumer_index == 0) + pool->consumer_index = pool->size - 1; + else + pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -325,7 +329,10 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 adapter->rx_buff_pool[pool].buff_size, DMA_FROM_DEVICE); - free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size; + free_index = adapter->rx_buff_pool[pool].producer_index; + adapter->rx_buff_pool[pool].producer_index + = (adapter->rx_buff_pool[pool].producer_index + 1) + % adapter->rx_buff_pool[pool].size; adapter->rx_buff_pool[pool].free_map[free_index] = index; mb(); @@ -437,6 +444,31 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) &adapter->rx_buff_pool[i]); } +static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, + union ibmveth_buf_desc rxq_desc, u64 mac_address) +{ + int rc, try_again = 1; + + /* After a kexec the adapter will still be open, so our attempt to + * open it will fail. So if we get a failure we free the adapter and + * try again, but only once. */ +retry: + rc = h_register_logical_lan(adapter->vdev->unit_address, + adapter->buffer_list_dma, rxq_desc.desc, + adapter->filter_list_dma, mac_address); + + if (rc != H_SUCCESS && try_again) { + do { + rc = h_free_logical_lan(adapter->vdev->unit_address); + } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); + + try_again = 0; + goto retry; + } + + return rc; +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; @@ -502,12 +534,9 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr); ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr); + h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - lpar_rc = h_register_logical_lan(adapter->vdev->unit_address, - adapter->buffer_list_dma, - rxq_desc.desc, - adapter->filter_list_dma, - mac_address); + lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address); if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc); @@ -905,6 +934,14 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ibmveth_poll_controller(struct net_device *dev) +{ + ibmveth_replenish_task(dev->priv); + ibmveth_interrupt(dev->irq, dev); +} +#endif + static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; @@ -977,6 +1014,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = ibmveth_poll_controller; +#endif netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); @@ -1132,7 +1172,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) { struct proc_dir_entry *entry; if (ibmveth_proc_dir) { - entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); if (!entry) { ibmveth_error_printk("Cannot create adapter proc entry"); } else { @@ -1147,7 +1189,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) { if (ibmveth_proc_dir) { - remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + remove_proc_entry(u_addr, ibmveth_proc_dir); } } diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index e963dbf816b..f56b00ee385 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1017,7 +1017,7 @@ static void ioc3_init(struct net_device *dev) struct ioc3_private *ip = netdev_priv(dev); struct ioc3 *ioc3 = ip->regs; - del_timer(&ip->ioc3_timer); /* Kill if running */ + del_timer_sync(&ip->ioc3_timer); /* Kill if running */ ioc3_w_emcr(EMCR_RST); /* Reset */ (void) ioc3_r_emcr(); /* Flush WB */ @@ -1081,7 +1081,7 @@ static int ioc3_close(struct net_device *dev) { struct ioc3_private *ip = netdev_priv(dev); - del_timer(&ip->ioc3_timer); + del_timer_sync(&ip->ioc3_timer); netif_stop_queue(dev); diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index be8a66e702b..3b4c4787593 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -15,8 +15,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. +* the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 4178b4b1d2d..82c10dec1b5 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -58,7 +58,11 @@ #include <linux/tcp.h> #include <linux/percpu.h> -static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); +struct pcpu_lstats { + unsigned long packets; + unsigned long bytes; +}; +static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats); #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) @@ -128,7 +132,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *lb_stats; + struct pcpu_lstats *lb_stats; skb_orphan(skb); @@ -149,16 +153,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; - lb_stats = &per_cpu(loopback_stats, get_cpu()); - lb_stats->rx_bytes += skb->len; - lb_stats->tx_bytes = lb_stats->rx_bytes; - lb_stats->rx_packets++; - lb_stats->tx_packets = lb_stats->rx_packets; - put_cpu(); + /* it's OK to use __get_cpu_var() because BHs are off */ + lb_stats = &__get_cpu_var(pcpu_lstats); + lb_stats->bytes += skb->len; + lb_stats->packets++; netif_rx(skb); - return(0); + return 0; } static struct net_device_stats loopback_stats; @@ -166,20 +168,21 @@ static struct net_device_stats loopback_stats; static struct net_device_stats *get_stats(struct net_device *dev) { struct net_device_stats *stats = &loopback_stats; + unsigned long bytes = 0; + unsigned long packets = 0; int i; - memset(stats, 0, sizeof(struct net_device_stats)); - for_each_possible_cpu(i) { - struct net_device_stats *lb_stats; + const struct pcpu_lstats *lb_stats; - lb_stats = &per_cpu(loopback_stats, i); - stats->rx_bytes += lb_stats->rx_bytes; - stats->tx_bytes += lb_stats->tx_bytes; - stats->rx_packets += lb_stats->rx_packets; - stats->tx_packets += lb_stats->tx_packets; + lb_stats = &per_cpu(pcpu_lstats, i); + bytes += lb_stats->bytes; + packets += lb_stats->packets; } - + stats->rx_packets = packets; + stats->tx_packets = packets; + stats->rx_bytes = bytes; + stats->tx_bytes = bytes; return stats; } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 2ffa3a59e70..9997081c6da 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2155,7 +2155,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp) for (offset = ETH_MIB_BAD_OCTETS_RECEIVED; offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS; offset += 4) - *(u32 *)((char *)p + offset) = read_mib(mp, offset); + *(u32 *)((char *)p + offset) += read_mib(mp, offset); p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW); p->good_octets_sent += @@ -2164,7 +2164,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp) for (offset = ETH_MIB_GOOD_FRAMES_SENT; offset <= ETH_MIB_LATE_COLLISION; offset += 4) - *(u32 *)((char *)p + offset) = read_mib(mp, offset); + *(u32 *)((char *)p + offset) += read_mib(mp, offset); } /* diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index fdbb0d7213b..806081b5973 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2416,7 +2416,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) * firmware image, and set tx.boundary to 4KB. */ -#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 #define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7 #define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h index e21ec9b2c70..ba7b8652c50 100644 --- a/drivers/net/myri_code.h +++ b/drivers/net/myri_code.h @@ -1,8 +1,8 @@ /* This is the Myrinet MCP code for LANai4.x */ /* Generated by cat $MYRI_HOME/lib/lanai/mcp4.dat > myri_code4.h */ -static unsigned int lanai4_code_off = 0x0000; /* half-word offset */ -static unsigned char lanai4_code[76256] __initdata = { +static unsigned int __devinitdata lanai4_code_off = 0x0000; /* half-word offset */ +static unsigned char __devinitdata lanai4_code[76256] = { 0xF2,0x0E, 0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, @@ -4774,8 +4774,8 @@ static unsigned char lanai4_code[76256] __initdata = { /* This is the LANai data */ -static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */ -static unsigned char lanai4_data[20472] __initdata; +static unsigned int __devinitdata lanai4_data_off = 0x94F0; /* half-word offset */ +static unsigned char __devinitdata lanai4_data[20472]; #ifdef SYMBOL_DEFINES_COMPILED diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 466b484c9fa..7747bfd99f9 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -168,7 +168,7 @@ static int myri_do_handshake(struct myri_eth *mp) return 0; } -static int myri_load_lanai(struct myri_eth *mp) +static int __devinit myri_load_lanai(struct myri_eth *mp) { struct net_device *dev = mp->dev; struct myri_shmem __iomem *shmem = mp->shmem; @@ -891,7 +891,7 @@ static void dump_eeprom(struct myri_eth *mp) } #endif -static int __init myri_ether_init(struct sbus_dev *sdev) +static int __devinit myri_ether_init(struct sbus_dev *sdev) { static int num; static unsigned version_printed; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index f1c75751cab..27f90b2139c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -214,6 +214,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_2 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(0x1259, 0xc107), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 }, @@ -1396,41 +1397,6 @@ static void rtl8169_netpoll(struct net_device *dev) } #endif -static void __rtl8169_set_mac_addr(struct net_device *dev, void __iomem *ioaddr) -{ - unsigned int i, j; - - RTL_W8(Cfg9346, Cfg9346_Unlock); - for (i = 0; i < 2; i++) { - __le32 l = 0; - - for (j = 0; j < 4; j++) { - l <<= 8; - l |= dev->dev_addr[4*i + j]; - } - RTL_W32(MAC0 + 4*i, cpu_to_be32(l)); - } - RTL_W8(Cfg9346, Cfg9346_Lock); -} - -static int rtl8169_set_mac_addr(struct net_device *dev, void *p) -{ - struct rtl8169_private *tp = netdev_priv(dev); - struct sockaddr *addr = p; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - - if (netif_running(dev)) { - spin_lock_irq(&tp->lock); - __rtl8169_set_mac_addr(dev, tp->mmio_addr); - spin_unlock_irq(&tp->lock); - } - return 0; -} - static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev, void __iomem *ioaddr) { @@ -1680,7 +1646,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->stop = rtl8169_close; dev->tx_timeout = rtl8169_tx_timeout; dev->set_multicast_list = rtl8169_set_rx_mode; - dev->set_mac_address = rtl8169_set_mac_addr; dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; @@ -1928,8 +1893,6 @@ rtl8169_hw_start(struct net_device *dev) /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16(IntrMask, rtl8169_intr_mask); - __rtl8169_set_mac_addr(dev, ioaddr); - netif_start_queue(dev); } @@ -2700,6 +2663,7 @@ static void rtl8169_down(struct net_device *dev) struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; unsigned int poll_locked = 0; + unsigned int intrmask; rtl8169_delete_timer(dev); @@ -2738,8 +2702,11 @@ core_down: * 2) dev->change_mtu * -> rtl8169_poll can not be issued again and re-enable the * interruptions. Let's simply issue the IRQ down sequence again. + * + * No loop if hotpluged or major error (0xffff). */ - if (RTL_R16(IntrMask)) + intrmask = RTL_R16(IntrMask); + if (intrmask && (intrmask != 0xffff)) goto core_down; rtl8169_tx_clear(tp); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index a231ab7d28d..33569ec9dbf 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5985,6 +5985,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1; } else { *skb = dev_alloc_skb(size); + if (!(*skb)) { + DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", + dev->name); + return -ENOMEM; + } ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, dev->mtu + 4, @@ -6007,7 +6012,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2; } else { *skb = dev_alloc_skb(size); - + if (!(*skb)) { + DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", + dev->name); + return -ENOMEM; + } ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index db2324939b6..1eae16b72b4 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2903,7 +2903,7 @@ sbmac_init_module(void) dev = alloc_etherdev(sizeof(struct sbmac_softc)); if (!dev) - return -ENOMEM; /* return ENOMEM */ + return -ENOMEM; printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a4a58e4e93a..b2949035f66 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -11,8 +11,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -43,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.8" +#define DRV_VERSION "1.9" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -197,8 +196,8 @@ static u32 skge_supported_modes(const struct skge_hw *hw) else if (hw->chip_id == CHIP_ID_YUKON) supported &= ~SUPPORTED_1000baseT_Half; } else - supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; + supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half + | SUPPORTED_FIBRE | SUPPORTED_Autoneg; return supported; } @@ -487,31 +486,37 @@ static void skge_get_pauseparam(struct net_device *dev, { struct skge_port *skge = netdev_priv(dev); - ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); - ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); + ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC) + || (skge->flow_control == FLOW_MODE_SYM_OR_REM); + ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND); - ecmd->autoneg = skge->autoneg; + ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause; } static int skge_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { struct skge_port *skge = netdev_priv(dev); + struct ethtool_pauseparam old; - skge->autoneg = ecmd->autoneg; - if (ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if (ecmd->rx_pause && !ecmd->tx_pause) - skge->flow_control = FLOW_MODE_REM_SEND; - else if (!ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_LOC_SEND; - else - skge->flow_control = FLOW_MODE_NONE; + skge_get_pauseparam(dev, &old); + + if (ecmd->autoneg != old.autoneg) + skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC; + else { + if (ecmd->rx_pause && ecmd->tx_pause) + skge->flow_control = FLOW_MODE_SYMMETRIC; + else if (ecmd->rx_pause && !ecmd->tx_pause) + skge->flow_control = FLOW_MODE_SYM_OR_REM; + else if (!ecmd->rx_pause && ecmd->tx_pause) + skge->flow_control = FLOW_MODE_LOC_SEND; + else + skge->flow_control = FLOW_MODE_NONE; + } if (netif_running(dev)) skge_phy_reset(skge); + return 0; } @@ -854,6 +859,23 @@ static int skge_rx_fill(struct net_device *dev) return 0; } +static const char *skge_pause(enum pause_status status) +{ + switch(status) { + case FLOW_STAT_NONE: + return "none"; + case FLOW_STAT_REM_SEND: + return "rx only"; + case FLOW_STAT_LOC_SEND: + return "tx_only"; + case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */ + return "both"; + default: + return "indeterminated"; + } +} + + static void skge_link_up(struct skge_port *skge) { skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), @@ -862,16 +884,13 @@ static void skge_link_up(struct skge_port *skge) netif_carrier_on(skge->netdev); netif_wake_queue(skge->netdev); - if (netif_msg_link(skge)) + if (netif_msg_link(skge)) { printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", skge->netdev->name, skge->speed, skge->duplex == DUPLEX_FULL ? "full" : "half", - (skge->flow_control == FLOW_MODE_NONE) ? "none" : - (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" : - (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" : - (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" : - "unknown"); + skge_pause(skge->flow_status)); + } } static void skge_link_down(struct skge_port *skge) @@ -884,6 +903,29 @@ static void skge_link_down(struct skge_port *skge) printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); } + +static void xm_link_down(struct skge_hw *hw, int port) +{ + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); + u16 cmd, msk; + + if (hw->phy_type == SK_PHY_XMAC) { + msk = xm_read16(hw, port, XM_IMSK); + msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND; + xm_write16(hw, port, XM_IMSK, msk); + } + + cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); + xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ + (void) xm_read16(hw, port, XM_MMU_CMD); + + if (netif_carrier_ok(dev)) + skge_link_down(skge); +} + static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) { int i; @@ -992,7 +1034,15 @@ static const u16 phy_pause_map[] = { [FLOW_MODE_NONE] = 0, [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, - [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, + [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, +}; + +/* special defines for FIBER (88E1011S only) */ +static const u16 fiber_pause_map[] = { + [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, + [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, + [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, + [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD, }; @@ -1008,14 +1058,7 @@ static void bcom_check_link(struct skge_hw *hw, int port) status = xm_phy_read(hw, port, PHY_BCOM_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); + xm_link_down(hw, port); return; } @@ -1048,20 +1091,19 @@ static void bcom_check_link(struct skge_hw *hw, int port) return; } - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (aux & PHY_B_AS_PAUSE_MSK) { case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } skge->speed = SPEED_1000; } @@ -1191,17 +1233,7 @@ static void xm_phy_init(struct skge_port *skge) if (skge->advertising & ADVERTISED_1000baseT_Full) ctrl |= PHY_X_AN_FD; - switch(skge->flow_control) { - case FLOW_MODE_NONE: - ctrl |= PHY_X_P_NO_PAUSE; - break; - case FLOW_MODE_LOC_SEND: - ctrl |= PHY_X_P_ASYM_MD; - break; - case FLOW_MODE_SYMMETRIC: - ctrl |= PHY_X_P_BOTH_MD; - break; - } + ctrl |= fiber_pause_map[skge->flow_control]; xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); @@ -1235,14 +1267,7 @@ static void xm_check_link(struct net_device *dev) status = xm_phy_read(hw, port, PHY_XMAC_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); + xm_link_down(hw, port); return; } @@ -1276,15 +1301,20 @@ static void xm_check_link(struct net_device *dev) } /* We are using IEEE 802.3z/D5.0 Table 37-4 */ - if (lpa & PHY_X_P_SYM_MD) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) - skge->flow_control = FLOW_MODE_REM_SEND; - else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) - skge->flow_control = FLOW_MODE_LOC_SEND; + if ((skge->flow_control == FLOW_MODE_SYMMETRIC || + skge->flow_control == FLOW_MODE_SYM_OR_REM) && + (lpa & PHY_X_P_SYM_MD)) + skge->flow_status = FLOW_STAT_SYMMETRIC; + else if (skge->flow_control == FLOW_MODE_SYM_OR_REM && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) + /* Enable PAUSE receive, disable PAUSE transmit */ + skge->flow_status = FLOW_STAT_REM_SEND; + else if (skge->flow_control == FLOW_MODE_LOC_SEND && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) + /* Disable PAUSE receive, enable PAUSE transmit */ + skge->flow_status = FLOW_STAT_LOC_SEND; else - skge->flow_control = FLOW_MODE_NONE; - + skge->flow_status = FLOW_STAT_NONE; skge->speed = SPEED_1000; } @@ -1568,6 +1598,10 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", skge->netdev->name, status); + if (hw->phy_type == SK_PHY_XMAC && + (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC))) + xm_link_down(hw, port); + if (status & XM_IS_TXF_UR) { xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; @@ -1582,7 +1616,7 @@ static void genesis_link_up(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u16 cmd; + u16 cmd, msk; u32 mode; cmd = xm_read16(hw, port, XM_MMU_CMD); @@ -1591,8 +1625,8 @@ static void genesis_link_up(struct skge_port *skge) * enabling pause frame reception is required for 1000BT * because the XMAC is not reset if the link is going down */ - if (skge->flow_control == FLOW_MODE_NONE || - skge->flow_control == FLOW_MODE_LOC_SEND) + if (skge->flow_status == FLOW_STAT_NONE || + skge->flow_status == FLOW_STAT_LOC_SEND) /* Disable Pause Frame Reception */ cmd |= XM_MMU_IGN_PF; else @@ -1602,8 +1636,8 @@ static void genesis_link_up(struct skge_port *skge) xm_write16(hw, port, XM_MMU_CMD, cmd); mode = xm_read32(hw, port, XM_MODE); - if (skge->flow_control == FLOW_MODE_SYMMETRIC || - skge->flow_control == FLOW_MODE_LOC_SEND) { + if (skge->flow_status== FLOW_STAT_SYMMETRIC || + skge->flow_status == FLOW_STAT_LOC_SEND) { /* * Configure Pause Frame Generation * Use internal and external Pause Frame Generation. @@ -1631,7 +1665,11 @@ static void genesis_link_up(struct skge_port *skge) } xm_write32(hw, port, XM_MODE, mode); - xm_write16(hw, port, XM_IMSK, XM_DEF_MSK); + msk = XM_DEF_MSK; + if (hw->phy_type != SK_PHY_XMAC) + msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ + + xm_write16(hw, port, XM_IMSK, msk); xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ @@ -1779,11 +1817,17 @@ static void yukon_init(struct skge_hw *hw, int port) adv |= PHY_M_AN_10_FD; if (skge->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - } else /* special defines for FIBER (88E1011S only) */ - adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; - /* Set Flow-control capabilities */ - adv |= phy_pause_map[skge->flow_control]; + /* Set Flow-control capabilities */ + adv |= phy_pause_map[skge->flow_control]; + } else { + if (skge->advertising & ADVERTISED_1000baseT_Full) + adv |= PHY_M_AN_1000X_AFD; + if (skge->advertising & ADVERTISED_1000baseT_Half) + adv |= PHY_M_AN_1000X_AHD; + + adv |= fiber_pause_map[skge->flow_control]; + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; @@ -1917,6 +1961,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) case FLOW_MODE_LOC_SEND: /* disable Rx flow-control */ reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; + break; + case FLOW_MODE_SYMMETRIC: + case FLOW_MODE_SYM_OR_REM: + /* enable Tx & Rx flow-control */ + break; } gma_write16(hw, port, GM_GP_CTRL, reg); @@ -2111,13 +2160,11 @@ static void yukon_link_down(struct skge_port *skge) ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); - if (skge->flow_control == FLOW_MODE_REM_SEND) { + if (skge->flow_status == FLOW_STAT_REM_SEND) { + ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); + ctrl |= PHY_M_AN_ASP; /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, - PHY_MARV_AUNE_ADV) - | PHY_M_AN_ASP); - + gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl); } yukon_reset(hw, port); @@ -2164,19 +2211,19 @@ static void yukon_phy_intr(struct skge_port *skge) /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (phystat & PHY_M_PS_PAUSE_MSK) { case PHY_M_PS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_M_PS_RX_P_EN: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_M_PS_TX_P_EN: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } - if (skge->flow_control == FLOW_MODE_NONE || + if (skge->flow_status == FLOW_STAT_NONE || (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); else @@ -3399,7 +3446,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* Auto speed and flow control */ skge->autoneg = AUTONEG_ENABLE; - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_control = FLOW_MODE_SYM_OR_REM; skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index d0b47d46cf9..537c0aaa1db 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2195,7 +2195,8 @@ enum { XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ }; -#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR)) +#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \ + XM_IS_RXF_OV | XM_IS_TXF_UR)) /* XM_HW_CFG 16 bit r/w Hardware Config Register */ @@ -2426,13 +2427,24 @@ struct skge_hw { struct mutex phy_mutex; }; -enum { - FLOW_MODE_NONE = 0, /* No Flow-Control */ - FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ - FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */ +enum pause_control { + FLOW_MODE_NONE = 1, /* No Flow-Control */ + FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ + FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or + * just the remote station may send PAUSE + */ +}; + +enum pause_status { + FLOW_STAT_INDETERMINATED=0, /* indeterminated */ + FLOW_STAT_NONE, /* No Flow Control */ + FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */ + FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */ + FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */ }; + struct skge_port { u32 msg_enable; struct skge_hw *hw; @@ -2445,9 +2457,10 @@ struct skge_port { struct net_device_stats net_stats; struct work_struct link_thread; + enum pause_control flow_control; + enum pause_status flow_status; u8 rx_csum; u8 blink_on; - u8 flow_control; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 459c845d664..16616f5440d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -10,8 +10,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -50,7 +49,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.9" +#define DRV_VERSION "1.10" #define PFX DRV_NAME " " /* @@ -96,9 +95,9 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); -static int idle_timeout = 100; +static int idle_timeout = 0; module_param(idle_timeout, int, 0); -MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)"); +MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)"); static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, @@ -284,6 +283,31 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) gma_write16(hw, port, GM_RX_CTRL, reg); } +/* flow control to advertise bits */ +static const u16 copper_fc_adv[] = { + [FC_NONE] = 0, + [FC_TX] = PHY_M_AN_ASP, + [FC_RX] = PHY_M_AN_PC, + [FC_BOTH] = PHY_M_AN_PC | PHY_M_AN_ASP, +}; + +/* flow control to advertise bits when using 1000BaseX */ +static const u16 fiber_fc_adv[] = { + [FC_BOTH] = PHY_M_P_BOTH_MD_X, + [FC_TX] = PHY_M_P_ASYM_MD_X, + [FC_RX] = PHY_M_P_SYM_MD_X, + [FC_NONE] = PHY_M_P_NO_PAUSE_X, +}; + +/* flow control to GMA disable bits */ +static const u16 gm_fc_disable[] = { + [FC_NONE] = GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS, + [FC_TX] = GM_GPCR_FC_RX_DIS, + [FC_RX] = GM_GPCR_FC_TX_DIS, + [FC_BOTH] = 0, +}; + + static void sky2_phy_init(struct sky2_hw *hw, unsigned port) { struct sky2_port *sky2 = netdev_priv(hw->dev[port]); @@ -356,16 +380,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } - ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); - if (sky2->autoneg == AUTONEG_DISABLE) - ctrl &= ~PHY_CT_ANE; - else - ctrl |= PHY_CT_ANE; - - ctrl |= PHY_CT_RESET; - gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); - - ctrl = 0; + ctrl = PHY_CT_RESET; ct1000 = 0; adv = PHY_AN_CSMA; reg = 0; @@ -384,20 +399,16 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) adv |= PHY_M_AN_10_FD; if (sky2->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; + + adv |= copper_fc_adv[sky2->flow_mode]; } else { /* special defines for FIBER (88E1040S only) */ if (sky2->advertising & ADVERTISED_1000baseT_Full) adv |= PHY_M_AN_1000X_AFD; if (sky2->advertising & ADVERTISED_1000baseT_Half) adv |= PHY_M_AN_1000X_AHD; - } - /* Set Flow-control capabilities */ - if (sky2->tx_pause && sky2->rx_pause) - adv |= PHY_AN_PAUSE_CAP; /* symmetric */ - else if (sky2->rx_pause && !sky2->tx_pause) - adv |= PHY_AN_PAUSE_ASYM | PHY_AN_PAUSE_CAP; - else if (!sky2->rx_pause && sky2->tx_pause) - adv |= PHY_AN_PAUSE_ASYM; /* local */ + adv |= fiber_fc_adv[sky2->flow_mode]; + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; @@ -422,25 +433,17 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->duplex == DUPLEX_FULL) { reg |= GM_GPCR_DUP_FULL; ctrl |= PHY_CT_DUP_MD; - } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) { - /* Turn off flow control for 10/100mbps */ - sky2->rx_pause = 0; - sky2->tx_pause = 0; - } + } else if (sky2->speed < SPEED_1000) + sky2->flow_mode = FC_NONE; - if (!sky2->rx_pause) - reg |= GM_GPCR_FC_RX_DIS; - if (!sky2->tx_pause) - reg |= GM_GPCR_FC_TX_DIS; + reg |= gm_fc_disable[sky2->flow_mode]; /* Forward pause packets to GMAC? */ - if (sky2->tx_pause || sky2->rx_pause) + if (sky2->flow_mode & FC_RX) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); - - ctrl |= PHY_CT_RESET; } gma_write16(hw, port, GM_GP_CTRL, reg); @@ -683,7 +686,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); + sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 512/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); if (hw->dev[port]->mtu > ETH_DATA_LEN) { /* set Tx GMAC FIFO Almost Empty Threshold */ @@ -695,16 +698,10 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) } -/* Assign Ram Buffer allocation. - * start and end are in units of 4k bytes - * ram registers are in units of 64bit words - */ -static void sky2_ramset(struct sky2_hw *hw, u16 q, u8 startk, u8 endk) +/* Assign Ram Buffer allocation in units of 64bit (8 bytes) */ +static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 end) { - u32 start, end; - - start = startk * 4096/8; - end = (endk * 4096/8) - 1; + pr_debug(PFX "q %d %#x %#x\n", q, start, end); sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR); sky2_write32(hw, RB_ADDR(q, RB_START), start); @@ -713,7 +710,7 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u8 startk, u8 endk) sky2_write32(hw, RB_ADDR(q, RB_RP), start); if (q == Q_R1 || q == Q_R2) { - u32 space = (endk - startk) * 4096/8; + u32 space = end - start + 1; u32 tp = space - space/4; /* On receive queue's set the thresholds @@ -1195,19 +1192,16 @@ static int sky2_up(struct net_device *dev) sky2_mac_init(hw, port); - /* Determine available ram buffer space (in 4K blocks). - * Note: not sure about the FE setting below yet - */ - if (hw->chip_id == CHIP_ID_YUKON_FE) - ramsize = 4; - else - ramsize = sky2_read8(hw, B2_E_0); + /* Determine available ram buffer space in qwords. */ + ramsize = sky2_read8(hw, B2_E_0) * 4096/8; - /* Give transmitter one third (rounded up) */ - rxspace = ramsize - (ramsize + 2) / 3; + if (ramsize > 6*1024/8) + rxspace = ramsize - (ramsize + 2) / 3; + else + rxspace = ramsize / 2; - sky2_ramset(hw, rxqaddr[port], 0, rxspace); - sky2_ramset(hw, txqaddr[port], rxspace, ramsize); + sky2_ramset(hw, rxqaddr[port], 0, rxspace-1); + sky2_ramset(hw, txqaddr[port], rxspace, ramsize-1); /* Make sure SyncQ is disabled */ sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL), @@ -1499,6 +1493,11 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); + /* Disable port IRQ */ + imask = sky2_read32(hw, B0_IMSK); + imask &= ~portirq_msk[port]; + sky2_write32(hw, B0_IMSK, imask); + sky2_gmac_reset(hw, port); /* Stop transmitter */ @@ -1549,11 +1548,6 @@ static int sky2_down(struct net_device *dev) sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); - /* Disable port IRQ */ - imask = sky2_read32(hw, B0_IMSK); - imask &= ~portirq_msk[port]; - sky2_write32(hw, B0_IMSK, imask); - sky2_phy_power(hw, port, 0); /* turn off LED's */ @@ -1605,6 +1599,12 @@ static void sky2_link_up(struct sky2_port *sky2) struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u16 reg; + static const char *fc_name[] = { + [FC_NONE] = "none", + [FC_TX] = "tx", + [FC_RX] = "rx", + [FC_BOTH] = "both", + }; /* enable Rx/Tx */ reg = gma_read16(hw, port, GM_GP_CTRL); @@ -1648,8 +1648,7 @@ static void sky2_link_up(struct sky2_port *sky2) "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", sky2->netdev->name, sky2->speed, sky2->duplex == DUPLEX_FULL ? "full" : "half", - (sky2->tx_pause && sky2->rx_pause) ? "both" : - sky2->tx_pause ? "tx" : sky2->rx_pause ? "rx" : "none"); + fc_name[sky2->flow_status]); } static void sky2_link_down(struct sky2_port *sky2) @@ -1664,7 +1663,7 @@ static void sky2_link_down(struct sky2_port *sky2) reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, reg); - if (sky2->rx_pause && !sky2->tx_pause) { + if (sky2->flow_status == FC_RX) { /* restore Asymmetric Pause bit */ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) @@ -1683,6 +1682,14 @@ static void sky2_link_down(struct sky2_port *sky2) sky2_phy_init(hw, port); } +static enum flow_control sky2_flow(int rx, int tx) +{ + if (rx) + return tx ? FC_BOTH : FC_RX; + else + return tx ? FC_TX : FC_NONE; +} + static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) { struct sky2_hw *hw = sky2->hw; @@ -1703,39 +1710,20 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) } sky2->speed = sky2_phy_speed(hw, aux); - if (sky2->speed == SPEED_1000) { - u16 ctl2 = gm_phy_read(hw, port, PHY_MARV_1000T_CTRL); - u16 lpa2 = gm_phy_read(hw, port, PHY_MARV_1000T_STAT); - if (lpa2 & PHY_B_1000S_MSF) { - printk(KERN_ERR PFX "%s: master/slave fault", - sky2->netdev->name); - return -1; - } - - if ((ctl2 & PHY_M_1000C_AFD) && (lpa2 & PHY_B_1000S_LP_FD)) - sky2->duplex = DUPLEX_FULL; - else - sky2->duplex = DUPLEX_HALF; - } else { - u16 adv = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); - if ((aux & adv) & PHY_AN_FULL) - sky2->duplex = DUPLEX_FULL; - else - sky2->duplex = DUPLEX_HALF; - } + sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; /* Pause bits are offset (9..8) */ if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) aux >>= 6; - sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0; - sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0; + sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, + aux & PHY_M_PS_TX_P_EN); - if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000 + if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) - sky2->rx_pause = sky2->tx_pause = 0; + sky2->flow_status = FC_NONE; - if (sky2->rx_pause || sky2->tx_pause) + if (aux & PHY_M_PS_RX_P_EN) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -1750,13 +1738,13 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(dev); u16 istatus, phystat; + if (!netif_running(dev)) + return; + spin_lock(&sky2->phy_lock); istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); - if (!netif_running(dev)) - goto out; - if (netif_msg_intr(sky2)) printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", sky2->netdev->name, istatus, phystat); @@ -1907,7 +1895,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); re->skb->ip_summed = CHECKSUM_NONE; - __skb_put(skb, length); + skb_put(skb, length); } return skb; } @@ -1970,7 +1958,7 @@ static struct sk_buff *receive_new(struct sky2_port *sky2, if (skb_shinfo(skb)->nr_frags) skb_put_frags(skb, hdr_space, length); else - skb_put(skb, hdr_space); + skb_put(skb, length); return skb; } @@ -2016,6 +2004,10 @@ oversize: error: ++sky2->net_stats.rx_errors; + if (status & GMR_FS_RX_FF_OV) { + sky2->net_stats.rx_fifo_errors++; + goto resubmit; + } if (netif_msg_rx_err(sky2) && net_ratelimit()) printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n", @@ -2027,8 +2019,6 @@ error: sky2->net_stats.rx_frame_errors++; if (status & GMR_FS_CRC_ERR) sky2->net_stats.rx_crc_errors++; - if (status & GMR_FS_RX_FF_OV) - sky2->net_stats.rx_fifo_errors++; goto resubmit; } @@ -2220,8 +2210,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) /* PCI-Express uncorrectable Error occurred */ u32 pex_err; - pex_err = sky2_pci_read32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS); + pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); if (net_ratelimit()) printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", @@ -2229,20 +2218,15 @@ static void sky2_hw_intr(struct sky2_hw *hw) /* clear the interrupt */ sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - sky2_pci_write32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS, - 0xffffffffUL); + sky2_pci_write32(hw, PEX_UNC_ERR_STAT, + 0xffffffffUL); sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - - /* In case of fatal error mask off to keep from getting stuck */ - if (pex_err & (PCI_ERR_UNC_POISON_TLP | PCI_ERR_UNC_FCP - | PCI_ERR_UNC_DLP)) { + if (pex_err & PEX_FATAL_ERRORS) { u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); hwmsk &= ~Y2_IS_PCI_EXP; sky2_write32(hw, B0_HWE_IMSK, hwmsk); } - } if (status & Y2_HWE_L1_MASK) @@ -2423,7 +2407,6 @@ static int sky2_reset(struct sky2_hw *hw) u16 status; u8 t8; int i; - u32 msk; sky2_write8(hw, B0_CTST, CS_RST_CLR); @@ -2464,13 +2447,9 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_MRST_CLR); /* clear any PEX errors */ - if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) { - hw->err_cap = pci_find_ext_capability(hw->pdev, PCI_EXT_CAP_ID_ERR); - if (hw->err_cap) - sky2_pci_write32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS, - 0xffffffffUL); - } + if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) + sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); hw->ports = 1; @@ -2527,10 +2506,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53); } - msk = Y2_HWE_ALL_MASK; - if (!hw->err_cap) - msk &= ~Y2_IS_PCI_EXP; - sky2_write32(hw, B0_HWE_IMSK, msk); + sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); for (i = 0; i < hw->ports; i++) sky2_gmac_reset(hw, i); @@ -2762,7 +2738,7 @@ static int sky2_nway_reset(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - if (sky2->autoneg != AUTONEG_ENABLE) + if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE) return -EINVAL; sky2_phy_reinit(sky2); @@ -2864,6 +2840,14 @@ static int sky2_set_mac_address(struct net_device *dev, void *p) return 0; } +static void inline sky2_add_filter(u8 filter[8], const u8 *addr) +{ + u32 bit; + + bit = ether_crc(ETH_ALEN, addr) & 63; + filter[bit >> 3] |= 1 << (bit & 7); +} + static void sky2_set_multicast(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); @@ -2872,7 +2856,10 @@ static void sky2_set_multicast(struct net_device *dev) struct dev_mc_list *list = dev->mc_list; u16 reg; u8 filter[8]; + int rx_pause; + static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; + rx_pause = (sky2->flow_status == FC_RX || sky2->flow_status == FC_BOTH); memset(filter, 0, sizeof(filter)); reg = gma_read16(hw, port, GM_RX_CTRL); @@ -2880,18 +2867,19 @@ static void sky2_set_multicast(struct net_device *dev) if (dev->flags & IFF_PROMISC) /* promiscuous */ reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16) /* all multicast */ + else if (dev->flags & IFF_ALLMULTI) memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0) /* no multicast */ + else if (dev->mc_count == 0 && !rx_pause) reg &= ~GM_RXCR_MCF_ENA; else { int i; reg |= GM_RXCR_MCF_ENA; - for (i = 0; list && i < dev->mc_count; i++, list = list->next) { - u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; - filter[bit / 8] |= 1 << (bit % 8); - } + if (rx_pause) + sky2_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < dev->mc_count; i++, list = list->next) + sky2_add_filter(filter, list->dmi_addr); } gma_write16(hw, port, GM_MC_ADDR_H1, @@ -3004,8 +2992,20 @@ static void sky2_get_pauseparam(struct net_device *dev, { struct sky2_port *sky2 = netdev_priv(dev); - ecmd->tx_pause = sky2->tx_pause; - ecmd->rx_pause = sky2->rx_pause; + switch (sky2->flow_mode) { + case FC_NONE: + ecmd->tx_pause = ecmd->rx_pause = 0; + break; + case FC_TX: + ecmd->tx_pause = 1, ecmd->rx_pause = 0; + break; + case FC_RX: + ecmd->tx_pause = 0, ecmd->rx_pause = 1; + break; + case FC_BOTH: + ecmd->tx_pause = ecmd->rx_pause = 1; + } + ecmd->autoneg = sky2->autoneg; } @@ -3015,10 +3015,10 @@ static int sky2_set_pauseparam(struct net_device *dev, struct sky2_port *sky2 = netdev_priv(dev); sky2->autoneg = ecmd->autoneg; - sky2->tx_pause = ecmd->tx_pause != 0; - sky2->rx_pause = ecmd->rx_pause != 0; + sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause); - sky2_phy_reinit(sky2); + if (netif_running(dev)) + sky2_phy_reinit(sky2); return 0; } @@ -3238,7 +3238,11 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->poll = sky2_poll; dev->weight = NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sky2_netpoll; + /* Network console (only works on port 0) + * because netpoll makes assumptions about NAPI + */ + if (port == 0) + dev->poll_controller = sky2_netpoll; #endif sky2 = netdev_priv(dev); @@ -3248,8 +3252,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, /* Auto speed and flow control */ sky2->autoneg = AUTONEG_ENABLE; - sky2->tx_pause = 1; - sky2->rx_pause = 1; + sky2->flow_mode = FC_BOTH; + sky2->duplex = -1; sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); @@ -3340,9 +3344,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) if (!hw->msi_detected) { /* MSI test failed, go back to INTx mode */ - printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, " - "switching to INTx mode. Please report this failure to " - "the PCI maintainer and include system chipset information.\n", + printk(KERN_INFO PFX "%s: No interrupt generated using MSI, " + "switching to INTx mode.\n", pci_name(pdev)); err = -EOPNOTSUPP; @@ -3350,6 +3353,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) } sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); free_irq(pdev->irq, hw); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f66109a96d9..6d2a23f66c9 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -6,15 +6,24 @@ #define ETH_JUMBO_MTU 9000 /* Maximum MTU supported */ -/* PCI device specific config registers */ +/* PCI config registers */ enum { PCI_DEV_REG1 = 0x40, PCI_DEV_REG2 = 0x44, + PCI_DEV_STATUS = 0x7c, PCI_DEV_REG3 = 0x80, PCI_DEV_REG4 = 0x84, PCI_DEV_REG5 = 0x88, }; +enum { + PEX_DEV_CAP = 0xe4, + PEX_DEV_CTRL = 0xe8, + PEX_DEV_STA = 0xea, + PEX_LNK_STAT = 0xf2, + PEX_UNC_ERR_STAT= 0x104, +}; + /* Yukon-2 */ enum pci_dev_reg_1 { PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */ @@ -63,6 +72,39 @@ enum pci_dev_reg_4 { PCI_STATUS_REC_MASTER_ABORT | \ PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) + +enum pex_dev_ctrl { + PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */ + PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */ + PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */ + PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */ + PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */ + PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */ + PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */ + PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */ + PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */ + PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */ + PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */ +}; +#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK) + +/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */ +enum pex_err { + PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */ + + PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */ + + PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */ + + PEX_COMP_TO = 1<<14, /* Completion Timeout */ + PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */ + PEX_POIS_TLP = 1<<12, /* Poisoned TLP */ + + PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */ + PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P), +}; + + enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -1534,7 +1576,7 @@ enum { GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR | GMR_FS_FRAGMENT | GMR_FS_LONG_ERR | - GMR_FS_MII_ERR | GMR_FS_BAD_FC | + GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; @@ -1786,6 +1828,13 @@ struct rx_ring_info { dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT]; }; +enum flow_control { + FC_NONE = 0, + FC_TX = 1, + FC_RX = 2, + FC_BOTH = 3, +}; + struct sky2_port { struct sky2_hw *hw; struct net_device *netdev; @@ -1818,13 +1867,13 @@ struct sky2_port { dma_addr_t rx_le_map; dma_addr_t tx_le_map; - u32 advertising; /* ADVERTISED_ bits */ + u16 advertising; /* ADVERTISED_ bits */ u16 speed; /* SPEED_1000, SPEED_100, ... */ u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ - u8 rx_pause; - u8 tx_pause; u8 rx_csum; + enum flow_control flow_mode; + enum flow_control flow_status; struct net_device_stats net_stats; @@ -1836,7 +1885,6 @@ struct sky2_hw { struct net_device *dev[2]; int pm_cap; - int err_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 636dbfcdf8c..a8640169fc7 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -398,6 +398,42 @@ 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) + +#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 diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 46a009085f7..418138dd6c6 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -55,12 +55,13 @@ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \ "<Jens.Osterkamp@de.ibm.com>"); MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; -module_param(rx_descriptors, int, 0644); -module_param(tx_descriptors, int, 0644); +module_param(rx_descriptors, int, 0444); +module_param(tx_descriptors, int, 0444); MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \ "in rx chains"); @@ -300,7 +301,7 @@ static int spider_net_init_chain(struct spider_net_card *card, struct spider_net_descr_chain *chain, struct spider_net_descr *start_descr, - int direction, int no) + int no) { int i; struct spider_net_descr *descr; @@ -315,7 +316,7 @@ spider_net_init_chain(struct spider_net_card *card, buf = pci_map_single(card->pdev, descr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(buf)) goto iommu_error; @@ -329,11 +330,6 @@ spider_net_init_chain(struct spider_net_card *card, (descr-1)->next = start_descr; start_descr->prev = descr-1; - descr = start_descr; - if (direction == PCI_DMA_FROMDEVICE) - for (i=0; i < no; i++, descr++) - descr->next_descr_addr = descr->next->bus_addr; - spin_lock_init(&chain->lock); chain->head = start_descr; chain->tail = start_descr; @@ -346,7 +342,7 @@ iommu_error: if (descr->bus_addr) pci_unmap_single(card->pdev, descr->bus_addr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); return -ENOMEM; } @@ -362,15 +358,15 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) struct spider_net_descr *descr; descr = card->rx_chain.head; - while (descr->next != card->rx_chain.head) { + do { if (descr->skb) { dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); + PCI_DMA_BIDIRECTIONAL); } descr = descr->next; - } + } while (descr != card->rx_chain.head); } /** @@ -645,26 +641,41 @@ static int spider_net_prepare_tx_descr(struct spider_net_card *card, struct sk_buff *skb) { - struct spider_net_descr *descr = card->tx_chain.head; + struct spider_net_descr *descr; dma_addr_t buf; + unsigned long flags; + int length; - buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + length = skb->len; + if (length < ETH_ZLEN) { + if (skb_pad(skb, ETH_ZLEN-length)) + return 0; + length = ETH_ZLEN; + } + + buf = pci_map_single(card->pdev, skb->data, length, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(buf)) { if (netif_msg_tx_err(card) && net_ratelimit()) pr_err("could not iommu-map packet (%p, %i). " - "Dropping packet\n", skb->data, skb->len); + "Dropping packet\n", skb->data, length); card->spider_stats.tx_iommu_map_error++; return -ENOMEM; } + spin_lock_irqsave(&card->tx_chain.lock, flags); + descr = card->tx_chain.head; + card->tx_chain.head = descr->next; + descr->buf_addr = buf; - descr->buf_size = skb->len; + descr->buf_size = length; descr->next_descr_addr = 0; descr->skb = skb; descr->data_status = 0; descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; + spin_unlock_irqrestore(&card->tx_chain.lock, flags); + if (skb->protocol == htons(ETH_P_IP)) switch (skb->nh.iph->protocol) { case IPPROTO_TCP: @@ -675,32 +686,51 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, break; } + /* Chain the bus address, so that the DMA engine finds this descr. */ descr->prev->next_descr_addr = descr->bus_addr; + card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ return 0; } -/** - * spider_net_release_tx_descr - processes a used tx descriptor - * @card: card structure - * @descr: descriptor to release - * - * releases a used tx descriptor (unmapping, freeing of skb) - */ -static inline void -spider_net_release_tx_descr(struct spider_net_card *card) +static int +spider_net_set_low_watermark(struct spider_net_card *card) { + unsigned long flags; + int status; + int cnt=0; + int i; struct spider_net_descr *descr = card->tx_chain.tail; - struct sk_buff *skb; - card->tx_chain.tail = card->tx_chain.tail->next; - descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; + /* Measure the length of the queue. Measurement does not + * need to be precise -- does not need a lock. */ + while (descr != card->tx_chain.head) { + status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; + if (status == SPIDER_NET_DESCR_NOT_IN_USE) + break; + descr = descr->next; + cnt++; + } - /* unmap the skb */ - skb = descr->skb; - pci_unmap_single(card->pdev, descr->buf_addr, skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); + /* If TX queue is short, don't even bother with interrupts */ + if (cnt < card->num_tx_desc/4) + return cnt; + + /* Set low-watermark 3/4th's of the way into the queue. */ + descr = card->tx_chain.tail; + cnt = (cnt*3)/4; + for (i=0;i<cnt; i++) + descr = descr->next; + + /* Set the new watermark, clear the old watermark */ + spin_lock_irqsave(&card->tx_chain.lock, flags); + descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; + if (card->low_watermark && card->low_watermark != descr) + card->low_watermark->dmac_cmd_status = + card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; + card->low_watermark = descr; + spin_unlock_irqrestore(&card->tx_chain.lock, flags); + return cnt; } /** @@ -719,21 +749,29 @@ static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { struct spider_net_descr_chain *chain = &card->tx_chain; + struct spider_net_descr *descr; + struct sk_buff *skb; + u32 buf_addr; + unsigned long flags; int status; - spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR); - while (chain->tail != chain->head) { - status = spider_net_get_descr_status(chain->tail); + spin_lock_irqsave(&chain->lock, flags); + descr = chain->tail; + + status = spider_net_get_descr_status(descr); switch (status) { case SPIDER_NET_DESCR_COMPLETE: card->netdev_stats.tx_packets++; - card->netdev_stats.tx_bytes += chain->tail->skb->len; + card->netdev_stats.tx_bytes += descr->skb->len; break; case SPIDER_NET_DESCR_CARDOWNED: - if (!brutal) + if (!brutal) { + spin_unlock_irqrestore(&chain->lock, flags); return 1; + } + /* fallthrough, if we release the descriptors * brutally (then we don't care about * SPIDER_NET_DESCR_CARDOWNED) */ @@ -750,11 +788,25 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) default: card->netdev_stats.tx_dropped++; - return 1; + if (!brutal) { + spin_unlock_irqrestore(&chain->lock, flags); + return 1; + } } - spider_net_release_tx_descr(card); - } + chain->tail = descr->next; + descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; + skb = descr->skb; + buf_addr = descr->buf_addr; + spin_unlock_irqrestore(&chain->lock, flags); + + /* unmap the skb */ + if (skb) { + int len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + pci_unmap_single(card->pdev, buf_addr, len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + } + } return 0; } @@ -763,8 +815,12 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) * @card: card structure * @descr: descriptor address to enable TX processing at * - * spider_net_kick_tx_dma writes the current tx chain head as start address - * of the tx descriptor chain and enables the transmission DMA engine + * This routine will start the transmit DMA running if + * it is not already running. This routine ned only be + * called when queueing a new packet to an empty tx queue. + * Writes the current tx chain head as start address + * of the tx descriptor chain and enables the transmission + * DMA engine. */ static inline void spider_net_kick_tx_dma(struct spider_net_card *card) @@ -804,65 +860,43 @@ out: static int spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { + int cnt; struct spider_net_card *card = netdev_priv(netdev); struct spider_net_descr_chain *chain = &card->tx_chain; - struct spider_net_descr *descr = chain->head; - unsigned long flags; - int result; - - spin_lock_irqsave(&chain->lock, flags); spider_net_release_tx_chain(card, 0); - if (chain->head->next == chain->tail->prev) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; - } + if ((chain->head->next == chain->tail->prev) || + (spider_net_prepare_tx_descr(card, skb) != 0)) { - if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) { card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; } - if (spider_net_prepare_tx_descr(card, skb) != 0) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_BUSY; - goto out; - } - - result = NETDEV_TX_OK; - - spider_net_kick_tx_dma(card); - card->tx_chain.head = card->tx_chain.head->next; - -out: - spin_unlock_irqrestore(&chain->lock, flags); - netif_wake_queue(netdev); - return result; + cnt = spider_net_set_low_watermark(card); + if (cnt < 5) + spider_net_kick_tx_dma(card); + return NETDEV_TX_OK; } /** * spider_net_cleanup_tx_ring - cleans up the TX ring * @card: card structure * - * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use - * interrupts to cleanup our TX ring) and returns sent packets to the stack - * by freeing them + * spider_net_cleanup_tx_ring is called by either the tx_timer + * or from the NAPI polling routine. + * This routine releases resources associted with transmitted + * packets, including updating the queue tail pointer. */ static void spider_net_cleanup_tx_ring(struct spider_net_card *card) { - unsigned long flags; - - spin_lock_irqsave(&card->tx_chain.lock, flags); - if ((spider_net_release_tx_chain(card, 0) != 0) && - (card->netdev->flags & IFF_UP)) + (card->netdev->flags & IFF_UP)) { spider_net_kick_tx_dma(card); - - spin_unlock_irqrestore(&card->tx_chain.lock, flags); + netif_wake_queue(card->netdev); + } } /** @@ -1053,6 +1087,7 @@ spider_net_poll(struct net_device *netdev, int *budget) int packets_to_do, packets_done = 0; int no_more_packets = 0; + spider_net_cleanup_tx_ring(card); packets_to_do = min(*budget, netdev->quota); while (packets_to_do) { @@ -1243,12 +1278,15 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_PHYINT: case SPIDER_NET_GMAC2INT: case SPIDER_NET_GMAC1INT: - case SPIDER_NET_GIPSINT: case SPIDER_NET_GFIFOINT: case SPIDER_NET_DMACINT: case SPIDER_NET_GSYSINT: break; */ + case SPIDER_NET_GIPSINT: + show_error = 0; + break; + case SPIDER_NET_GPWOPCMPINT: /* PHY write operation completed */ show_error = 0; @@ -1307,9 +1345,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GDTDCEINT: /* chain end. If a descriptor should be sent, kick off * tx dma - if (card->tx_chain.tail == card->tx_chain.head) + if (card->tx_chain.tail != card->tx_chain.head) spider_net_kick_tx_dma(card); - show_error = 0; */ + */ + show_error = 0; break; /* case SPIDER_NET_G1TMCNTINT: not used. print a message */ @@ -1354,7 +1393,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) if (netif_msg_intr(card)) pr_err("got descriptor chain end interrupt, " "restarting DMAC %c.\n", - 'D'+i-SPIDER_NET_GDDDCEINT); + 'D'-(i-SPIDER_NET_GDDDCEINT)/3); spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); show_error = 0; @@ -1423,8 +1462,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) } if ((show_error) && (netif_msg_intr(card))) - pr_err("Got error interrupt, GHIINT0STS = 0x%08x, " + pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, " "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n", + card->netdev->name, status_reg, error_reg1, error_reg2); /* clear interrupt sources */ @@ -1460,6 +1500,8 @@ spider_net_interrupt(int irq, void *ptr) spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } + if (status_reg & SPIDER_NET_TXINT) + netif_rx_schedule(netdev); if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1599,7 +1641,7 @@ spider_net_enable_card(struct spider_net_card *card) SPIDER_NET_INT2_MASK_VALUE); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, - SPIDER_NET_GDTDCEIDIS); + SPIDER_NET_GDTBSTA | SPIDER_NET_GDTDCEIDIS); } /** @@ -1615,17 +1657,26 @@ int spider_net_open(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - int result; + struct spider_net_descr *descr; + int i, result; result = -ENOMEM; if (spider_net_init_chain(card, &card->tx_chain, card->descr, - PCI_DMA_TODEVICE, card->tx_desc)) + card->num_tx_desc)) goto alloc_tx_failed; + + card->low_watermark = NULL; + + /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->rx_desc, - PCI_DMA_FROMDEVICE, card->rx_desc)) + card->descr + card->num_tx_desc, + card->num_rx_desc)) goto alloc_rx_failed; + descr = card->rx_chain.head; + for (i=0; i < card->num_rx_desc; i++, descr++) + descr->next_descr_addr = descr->next->bus_addr; + /* allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; @@ -1878,10 +1929,7 @@ spider_net_stop(struct net_device *netdev) spider_net_disable_rxdmac(card); /* release chains */ - if (spin_trylock(&card->tx_chain.lock)) { - spider_net_release_tx_chain(card, 1); - spin_unlock(&card->tx_chain.lock); - } + spider_net_release_tx_chain(card, 1); spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); @@ -2012,8 +2060,8 @@ 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; + card->num_tx_desc = tx_descriptors; + card->num_rx_desc = rx_descriptors; spider_net_setup_netdev_ops(netdev); @@ -2252,6 +2300,8 @@ static struct pci_driver spider_net_driver = { */ static int __init spider_net_init(void) { + printk(KERN_INFO "Spidernet version %s.\n", VERSION); + if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) { rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN; pr_info("adjusting rx descriptors to %i.\n", rx_descriptors); diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index a59deda2f95..b3b46119b42 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -24,6 +24,8 @@ #ifndef _SPIDER_NET_H #define _SPIDER_NET_H +#define VERSION "1.1 A" + #include "sungem_phy.h" extern int spider_net_stop(struct net_device *netdev); @@ -47,7 +49,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_TX_DESCRIPTORS_MIN 16 #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 -#define SPIDER_NET_TX_TIMER 20 +#define SPIDER_NET_TX_TIMER (HZ/5) #define SPIDER_NET_RX_CSUM_DEFAULT 1 @@ -189,7 +191,9 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_MACMODE_VALUE 0x00000001 #define SPIDER_NET_BURSTLMT_VALUE 0x00000200 /* about 16 us */ -/* 1(0) enable r/tx dma +/* DMAC control register GDMACCNTR + * + * 1(0) enable r/tx dma * 0000000 fixed to 0 * * 000000 fixed to 0 @@ -198,6 +202,7 @@ extern char spider_net_driver_name[]; * * 000000 fixed to 0 * 00 burst alignment: 128 bytes + * 11 burst alignment: 1024 bytes * * 00000 fixed to 0 * 0 descr writeback size 32 bytes @@ -208,10 +213,13 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_DMA_RX_VALUE 0x80000000 #define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003 /* to set TX_DMA_EN */ -#define SPIDER_NET_TX_DMA_EN 0x80000000 -#define SPIDER_NET_GDTDCEIDIS 0x00000002 -#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ - SPIDER_NET_GDTDCEIDIS +#define SPIDER_NET_TX_DMA_EN 0x80000000 +#define SPIDER_NET_GDTBSTA 0x00000300 +#define SPIDER_NET_GDTDCEIDIS 0x00000002 +#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ + SPIDER_NET_GDTBSTA | \ + SPIDER_NET_GDTDCEIDIS + #define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003 /* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */ @@ -320,13 +328,10 @@ enum spider_net_int2_status { SPIDER_NET_GRISPDNGINT }; -#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \ - (1 << SPIDER_NET_GDTDCEINT) | \ - (1 << SPIDER_NET_GDTFDCINT) ) +#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GDTFDCINT) ) -/* we rely on flagged descriptor interrupts*/ -#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \ - (1 << SPIDER_NET_GRMFLLINT) ) +/* We rely on flagged descriptor interrupts */ +#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) #define SPIDER_NET_ERRINT ( 0xffffffff & \ (~SPIDER_NET_TXINT) & \ @@ -349,6 +354,7 @@ enum spider_net_int2_status { #define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000 +#define SPIDER_NET_DESCR_TXDESFLG 0x00800000 struct spider_net_descr { /* as defined by the hardware */ @@ -433,6 +439,7 @@ struct spider_net_card { struct spider_net_descr_chain tx_chain; struct spider_net_descr_chain rx_chain; + struct spider_net_descr *low_watermark; struct net_device_stats netdev_stats; @@ -448,8 +455,8 @@ struct spider_net_card { /* for ethtool */ int msg_enable; - int rx_desc; - int tx_desc; + int num_rx_desc; + int num_tx_desc; struct spider_net_extra_stats spider_stats; struct spider_net_descr descr[0]; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 589e43658de..91b99510291 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -76,7 +76,7 @@ spider_net_ethtool_get_drvinfo(struct net_device *netdev, /* clear and fill out info */ memset(drvinfo, 0, sizeof(struct ethtool_drvinfo)); strncpy(drvinfo->driver, spider_net_driver_name, 32); - strncpy(drvinfo->version, "0.1", 32); + strncpy(drvinfo->version, VERSION, 32); strcpy(drvinfo->fw_version, "no information"); strncpy(drvinfo->bus_info, pci_name(card->pdev), 32); } @@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, struct spider_net_card *card = netdev->priv; ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; - ering->tx_pending = card->tx_desc; + ering->tx_pending = card->num_tx_desc; ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; - ering->rx_pending = card->rx_desc; + ering->rx_pending = card->num_rx_desc; } static int spider_net_get_stats_count(struct net_device *netdev) diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index d1d1885b029..a3220a96524 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -330,7 +330,7 @@ out2: out1: free_netdev(dev); out: - iounmap((void *)ioaddr); + iounmap((void __iomem *)ioaddr); return ERR_PTR(err); } diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 91c76544e4d..b865db363ba 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -286,7 +286,7 @@ struct net_device * __init sun3lance_probe(int unit) out1: #ifdef CONFIG_SUN3 - iounmap((void *)dev->base_addr); + iounmap((void __iomem *)dev->base_addr); #endif out: free_netdev(dev); @@ -326,7 +326,7 @@ static int __init lance_probe( struct net_device *dev) ioaddr_probe[1] = tmp2; #ifdef CONFIG_SUN3 - iounmap((void *)ioaddr); + iounmap((void __iomem *)ioaddr); #endif return 0; } @@ -956,7 +956,7 @@ void cleanup_module(void) { unregister_netdev(sun3lance_dev); #ifdef CONFIG_SUN3 - iounmap((void *)sun3lance_dev->base_addr); + iounmap((void __iomem *)sun3lance_dev->base_addr); #endif free_netdev(sun3lance_dev); } diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 6439b0cef1e..18f88853e1e 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -42,7 +42,7 @@ #define DRV_RELDATE "11/24/03" #define DRV_AUTHOR "David S. Miller (davem@redhat.com)" -static char version[] __initdata = +static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 327836b1014..c20bb998e0e 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.66" -#define DRV_MODULE_RELDATE "September 23, 2006" +#define DRV_MODULE_VERSION "3.69" +#define DRV_MODULE_RELDATE "November 15, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -129,7 +129,7 @@ #define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64) /* minimum number of free TX descriptors required to wake up TX process */ -#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4) +#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) @@ -3075,10 +3075,10 @@ static void tg3_tx(struct tg3 *tp) smp_mb(); if (unlikely(netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) { + (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) { netif_tx_lock(tp->dev); if (netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)) + (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))) netif_wake_queue(tp->dev); netif_tx_unlock(tp->dev); } @@ -3928,7 +3928,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tp->tx_prod = entry; if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH) + if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) netif_wake_queue(tp->dev); } @@ -4143,7 +4143,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) tp->tx_prod = entry; if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH) + if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) netif_wake_queue(tp->dev); } @@ -4728,10 +4728,11 @@ static int tg3_poll_fw(struct tg3 *tp) u32 val; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - for (i = 0; i < 400; i++) { + /* Wait up to 20ms for init done. */ + for (i = 0; i < 200; i++) { if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE) return 0; - udelay(10); + udelay(100); } return -ENODEV; } @@ -6014,7 +6015,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_abort_hw(tp, 1); } - if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) && reset_phy) + if (reset_phy) tg3_phy_reset(tp); err = tg3_chip_reset(tp); @@ -6574,7 +6575,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); } - err = tg3_setup_phy(tp, reset_phy); + err = tg3_setup_phy(tp, 0); if (err) return err; @@ -6978,8 +6979,10 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); err = tg3_set_power_state(tp, PCI_D0); - if (err) + if (err) { + tg3_full_unlock(tp); return err; + } tg3_disable_ints(tp); tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; @@ -8106,7 +8109,10 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) || (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || - (ering->tx_pending > TG3_TX_RING_SIZE - 1)) + (ering->tx_pending > TG3_TX_RING_SIZE - 1) || + (ering->tx_pending <= MAX_SKB_FRAGS) || + ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) && + (ering->tx_pending <= (MAX_SKB_FRAGS * 3)))) return -EINVAL; if (netif_running(dev)) { @@ -10209,7 +10215,7 @@ skip_phy_reset: static void __devinit tg3_read_partno(struct tg3 *tp) { unsigned char vpd_data[256]; - int i; + unsigned int i; u32 magic; if (tg3_nvram_read_swab(tp, 0x0, &magic)) @@ -10255,9 +10261,9 @@ static void __devinit tg3_read_partno(struct tg3 *tp) } /* Now parse and find the part number. */ - for (i = 0; i < 256; ) { + for (i = 0; i < 254; ) { unsigned char val = vpd_data[i]; - int block_end; + unsigned int block_end; if (val == 0x82 || val == 0x91) { i = (i + 3 + @@ -10273,21 +10279,26 @@ static void __devinit tg3_read_partno(struct tg3 *tp) (vpd_data[i + 1] + (vpd_data[i + 2] << 8))); i += 3; - while (i < block_end) { + + if (block_end > 256) + goto out_not_found; + + while (i < (block_end - 2)) { if (vpd_data[i + 0] == 'P' && vpd_data[i + 1] == 'N') { int partno_len = vpd_data[i + 2]; - if (partno_len > 24) + i += 3; + if (partno_len > 24 || (partno_len + i) > 256) goto out_not_found; memcpy(tp->board_part_number, - &vpd_data[i + 3], - partno_len); + &vpd_data[i], partno_len); /* Success. */ return; } + i += 3 + vpd_data[i + 2]; } /* Part number not found. */ @@ -10357,7 +10368,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) u32 pci_state_reg, grc_misc_cfg; u32 val; u16 pci_cmd; - int err; + int err, pcie_cap; /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. @@ -10532,8 +10543,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; - if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) + pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); + if (pcie_cap != 0) { tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u16 lnkctl; + + pci_read_config_word(tp->pdev, + pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) + tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + } + } /* If we have an AMD 762 or VIA K8T800 chipset, write * reordering to the mailbox registers done by the host @@ -11800,6 +11822,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; } else { diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 4f756960db2..cb7dbb63c9d 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -370,6 +370,10 @@ static int __init proteon_init(void) dev->dma = dma[i]; pdev = platform_device_register_simple("proteon", i, NULL, 0); + if (IS_ERR(pdev)) { + free_netdev(dev); + continue; + } err = setup_card(dev, &pdev->dev); if (!err) { proteon_dev[i] = pdev; @@ -385,9 +389,10 @@ static int __init proteon_init(void) /* Probe for cards. */ if (num == 0) { printk(KERN_NOTICE "proteon.c: No cards found.\n"); - return (-ENODEV); + platform_driver_unregister(&proteon_driver); + return -ENODEV; } - return (0); + return 0; } static void __exit proteon_cleanup(void) diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index d6ba41cf311..33afea31d87 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -380,6 +380,10 @@ static int __init sk_isa_init(void) dev->dma = dma[i]; pdev = platform_device_register_simple("skisa", i, NULL, 0); + if (IS_ERR(pdev)) { + free_netdev(dev); + continue; + } err = setup_card(dev, &pdev->dev); if (!err) { sk_isa_dev[i] = pdev; @@ -395,9 +399,10 @@ static int __init sk_isa_init(void) /* Probe for cards. */ if (num == 0) { printk(KERN_NOTICE "skisa.c: No cards found.\n"); - return (-ENODEV); + platform_driver_unregister(&sk_isa_driver); + return -ENODEV; } - return (0); + return 0; } static void __exit sk_isa_cleanup(void) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 2cfd9634895..f6b3a94e97b 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1730,7 +1730,7 @@ static void __init de21040_get_media_info(struct de_private *de) } /* Note: this routine returns extra data bits for size detection. */ -static unsigned __init tulip_read_eeprom(void __iomem *regs, int location, int addr_len) +static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len) { int i; unsigned retval = 0; @@ -1926,7 +1926,7 @@ bad_srom: goto fill_defaults; } -static int __init de_init_one (struct pci_dev *pdev, +static int __devinit de_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; @@ -2082,7 +2082,7 @@ err_out_free: return rc; } -static void __exit de_remove_one (struct pci_dev *pdev) +static void __devexit de_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct de_private *de = dev->priv; @@ -2164,7 +2164,7 @@ static struct pci_driver de_driver = { .name = DRV_NAME, .id_table = de_pci_tbl, .probe = de_init_one, - .remove = __exit_p(de_remove_one), + .remove = __devexit_p(de_remove_one), #ifdef CONFIG_PM .suspend = de_suspend, .resume = de_resume, diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 12cd7b561f3..b3788801106 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2,14 +2,11 @@ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. * * Author: Shlomi Gridish <gridish@freescale.com> + * Li Yang <leoli@freescale.com> * * Description: * QE UCC Gigabit Ethernet Driver * - * Changelog: - * Jul 6, 2006 Li Yang <LeoLi@freescale.com> - * - 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 @@ -31,9 +28,9 @@ #include <linux/dma-mapping.h> #include <linux/fsl_devices.h> #include <linux/ethtool.h> -#include <linux/platform_device.h> #include <linux/mii.h> +#include <asm/of_device.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> @@ -70,7 +67,7 @@ static DEFINE_SPINLOCK(ugeth_lock); -static ucc_geth_info_t ugeth_primary_info = { +static struct ucc_geth_info ugeth_primary_info = { .uf_info = { .bd_mem_part = MEM_PART_SYSTEM, .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, @@ -163,7 +160,7 @@ static ucc_geth_info_t ugeth_primary_info = { .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, }; -static ucc_geth_info_t ugeth_info[8]; +static struct ucc_geth_info ugeth_info[8]; #ifdef DEBUG static void mem_disp(u8 *addr, int size) @@ -219,8 +216,8 @@ static struct list_head *dequeue(struct list_head *lh) } } -static int get_interface_details(enet_interface_e enet_interface, - enet_speed_e *speed, +static int get_interface_details(enum enet_interface enet_interface, + enum enet_speed *speed, int *r10m, int *rmm, int *rpm, @@ -283,7 +280,7 @@ static int get_interface_details(enet_interface_e enet_interface, return 0; } -static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd) +static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) { struct sk_buff *skb = NULL; @@ -303,21 +300,19 @@ static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd) skb->dev = ugeth->dev; - BD_BUFFER_SET(bd, + out_be32(&((struct qe_bd *)bd)->buf, 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))); + out_be32((u32 *)bd, (R_E | R_I | (in_be32((u32 *)bd) & R_W))); return skb; } -static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ) +static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ) { u8 *bd; u32 bd_status; @@ -328,7 +323,7 @@ static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ) i = 0; do { - bd_status = BD_STATUS_AND_LENGTH(bd); + bd_status = in_be32((u32*)bd); skb = get_new_skb(ugeth, bd); if (!skb) /* If can not allocate data buffer, @@ -338,19 +333,19 @@ static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ) ugeth->rx_skbuff[rxQ][i] = skb; /* advance the BD pointer */ - bd += UCC_GETH_SIZE_OF_BD; + bd += sizeof(struct qe_bd); i++; } while (!(bd_status & R_W)); return 0; } -static int fill_init_enet_entries(ucc_geth_private_t *ugeth, +static int fill_init_enet_entries(struct ucc_geth_private *ugeth, volatile u32 *p_start, u8 num_entries, u32 thread_size, u32 thread_alignment, - qe_risc_allocation_e risc, + enum qe_risc_allocation risc, int skip_page_for_first_entry) { u32 init_enet_offset; @@ -383,10 +378,10 @@ static int fill_init_enet_entries(ucc_geth_private_t *ugeth, return 0; } -static int return_init_enet_entries(ucc_geth_private_t *ugeth, +static int return_init_enet_entries(struct ucc_geth_private *ugeth, volatile u32 *p_start, u8 num_entries, - qe_risc_allocation_e risc, + enum qe_risc_allocation risc, int skip_page_for_first_entry) { u32 init_enet_offset; @@ -416,11 +411,11 @@ static int return_init_enet_entries(ucc_geth_private_t *ugeth, } #ifdef DEBUG -static int dump_init_enet_entries(ucc_geth_private_t *ugeth, +static int dump_init_enet_entries(struct ucc_geth_private *ugeth, volatile u32 *p_start, u8 num_entries, u32 thread_size, - qe_risc_allocation_e risc, + enum qe_risc_allocation risc, int skip_page_for_first_entry) { u32 init_enet_offset; @@ -456,14 +451,14 @@ static int dump_init_enet_entries(ucc_geth_private_t *ugeth, #endif #ifdef CONFIG_UGETH_FILTERING -static enet_addr_container_t *get_enet_addr_container(void) +static struct enet_addr_container *get_enet_addr_container(void) { - enet_addr_container_t *enet_addr_cont; + struct enet_addr_container *enet_addr_cont; /* allocate memory */ - enet_addr_cont = kmalloc(sizeof(enet_addr_container_t), GFP_KERNEL); + enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL); if (!enet_addr_cont) { - ugeth_err("%s: No memory for enet_addr_container_t object.", + ugeth_err("%s: No memory for enet_addr_container object.", __FUNCTION__); return NULL; } @@ -472,45 +467,43 @@ static enet_addr_container_t *get_enet_addr_container(void) } #endif /* CONFIG_UGETH_FILTERING */ -static void put_enet_addr_container(enet_addr_container_t *enet_addr_cont) +static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont) { kfree(enet_addr_cont); } +static int set_mac_addr(__be16 __iomem *reg, u8 *mac) +{ + out_be16(®[0], ((u16)mac[5] << 8) | mac[4]); + out_be16(®[1], ((u16)mac[3] << 8) | mac[2]); + out_be16(®[2], ((u16)mac[1] << 8) | mac[0]); +} + #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) +static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth, + u8 *p_enet_addr, u8 paddr_num) { - ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; if (!(paddr_num < NUM_OF_PADDRS)) { - ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + ugeth_warn("%s: Illegal paddr_num.", __FUNCTION__); return -EINVAL; } p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + (struct ucc_geth_82xx_address_filtering_pram *) 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])); - + set_mac_addr(&p_82xx_addr_filt->paddr[paddr_num].h, p_enet_addr); return 0; } #endif /* CONFIG_UGETH_FILTERING */ -static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num) +static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) { - ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; if (!(paddr_num < NUM_OF_PADDRS)) { ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); @@ -518,7 +511,7 @@ static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num) } p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> addressfiltering; /* Writing address ff.ff.ff.ff.ff.ff disables address @@ -530,14 +523,14 @@ static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num) return 0; } -static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth, - enet_addr_t *p_enet_addr) +static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth, + u8 *p_enet_addr) { - ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; u32 cecr_subblock; p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> addressfiltering; cecr_subblock = @@ -546,25 +539,18 @@ static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth, /* 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])); + + set_mac_addr(&p_82xx_addr_filt->taddr.h, p_enet_addr); qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock, - (u8) QE_CR_PROTOCOL_ETHERNET, 0); + QE_CR_PROTOCOL_ETHERNET, 0); } #ifdef CONFIG_UGETH_MAGIC_PACKET -static void magic_packet_detection_enable(ucc_geth_private_t *ugeth) +static void magic_packet_detection_enable(struct ucc_geth_private *ugeth) { - ucc_fast_private_t *uccf; - ucc_geth_t *ug_regs; + struct ucc_fast_private *uccf; + struct ucc_geth *ug_regs; u32 maccfg2, uccm; uccf = ugeth->uccf; @@ -581,10 +567,10 @@ static void magic_packet_detection_enable(ucc_geth_private_t *ugeth) out_be32(&ug_regs->maccfg2, maccfg2); } -static void magic_packet_detection_disable(ucc_geth_private_t *ugeth) +static void magic_packet_detection_disable(struct ucc_geth_private *ugeth) { - ucc_fast_private_t *uccf; - ucc_geth_t *ug_regs; + struct ucc_fast_private *uccf; + struct ucc_geth *ug_regs; u32 maccfg2, uccm; uccf = ugeth->uccf; @@ -602,26 +588,26 @@ static void magic_packet_detection_disable(ucc_geth_private_t *ugeth) } #endif /* MAGIC_PACKET */ -static inline int compare_addr(enet_addr_t *addr1, enet_addr_t *addr2) +static inline int compare_addr(u8 **addr1, u8 **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 * +static void get_statistics(struct ucc_geth_private *ugeth, + struct ucc_geth_tx_firmware_statistics * tx_firmware_statistics, - ucc_geth_rx_firmware_statistics_t * + struct ucc_geth_rx_firmware_statistics * rx_firmware_statistics, - ucc_geth_hardware_statistics_t *hardware_statistics) + struct ucc_geth_hardware_statistics *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; + struct ucc_fast *uf_regs; + struct ucc_geth *ug_regs; + struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram; + struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram; ug_regs = ugeth->ug_regs; - uf_regs = (ucc_fast_t *) ug_regs; + uf_regs = (struct ucc_fast *) ug_regs; p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram; p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram; @@ -727,7 +713,7 @@ static void get_statistics(ucc_geth_private_t *ugeth, } } -static void dump_bds(ucc_geth_private_t *ugeth) +static void dump_bds(struct ucc_geth_private *ugeth) { int i; int length; @@ -736,7 +722,7 @@ static void dump_bds(ucc_geth_private_t *ugeth) if (ugeth->p_tx_bd_ring[i]) { length = (ugeth->ug_info->bdRingLenTx[i] * - UCC_GETH_SIZE_OF_BD); + sizeof(struct qe_bd)); ugeth_info("TX BDs[%d]", i); mem_disp(ugeth->p_tx_bd_ring[i], length); } @@ -745,14 +731,14 @@ static void dump_bds(ucc_geth_private_t *ugeth) if (ugeth->p_rx_bd_ring[i]) { length = (ugeth->ug_info->bdRingLenRx[i] * - UCC_GETH_SIZE_OF_BD); + sizeof(struct qe_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) +static void dump_regs(struct ucc_geth_private *ugeth) { int i; @@ -893,7 +879,7 @@ static void dump_regs(ucc_geth_private_t *ugeth) 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)); + sizeof(struct ucc_geth_thread_data_tx)); } } if (ugeth->p_thread_data_rx) { @@ -927,7 +913,7 @@ static void dump_regs(ucc_geth_private_t *ugeth) 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)); + sizeof(struct ucc_geth_thread_data_rx)); } } if (ugeth->p_exf_glbl_param) { @@ -1105,7 +1091,7 @@ static void dump_regs(ucc_geth_private_t *ugeth) 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)); + sizeof(struct ucc_geth_send_queue_qd)); } } if (ugeth->p_scheduler) { @@ -1187,7 +1173,7 @@ static void dump_regs(ucc_geth_private_t *ugeth) qe_muram_addr(in_be32 (&ugeth->p_rx_bd_qs_tbl[i]. bdbaseptr)), - sizeof(ucc_geth_rx_prefetched_bds_t)); + sizeof(struct ucc_geth_rx_prefetched_bds)); } } if (ugeth->p_init_enet_param_shadow) { @@ -1198,7 +1184,7 @@ static void dump_regs(ucc_geth_private_t *ugeth) mem_disp((u8 *) ugeth->p_init_enet_param_shadow, sizeof(*ugeth->p_init_enet_param_shadow)); - size = sizeof(ucc_geth_thread_rx_pram_t); + size = sizeof(struct ucc_geth_thread_rx_pram); if (ugeth->ug_info->rxExtendedFiltering) { size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; @@ -1216,7 +1202,7 @@ static void dump_regs(ucc_geth_private_t *ugeth) &(ugeth->p_init_enet_param_shadow-> txthread[0]), ENET_INIT_PARAM_MAX_ENTRIES_TX, - sizeof(ucc_geth_thread_tx_pram_t), + sizeof(struct ucc_geth_thread_tx_pram), ugeth->ug_info->riscTx, 0); dump_init_enet_entries(ugeth, &(ugeth->p_init_enet_param_shadow-> @@ -1578,12 +1564,12 @@ static int init_min_frame_len(u16 min_frame_length, return 0; } -static int adjust_enet_interface(ucc_geth_private_t *ugeth) +static int adjust_enet_interface(struct ucc_geth_private *ugeth) { - ucc_geth_info_t *ug_info; - ucc_geth_t *ug_regs; - ucc_fast_t *uf_regs; - enet_speed_e speed; + struct ucc_geth_info *ug_info; + struct ucc_geth *ug_regs; + struct ucc_fast *uf_regs; + enum enet_speed speed; int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = 0, limited_to_full_duplex = 0; u32 upsmr, maccfg2, utbipar, tbiBaseAddress; @@ -1691,8 +1677,8 @@ static int adjust_enet_interface(ucc_geth_private_t *ugeth) */ static void adjust_link(struct net_device *dev) { - ucc_geth_private_t *ugeth = netdev_priv(dev); - ucc_geth_t *ug_regs; + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_geth *ug_regs; u32 tempval; struct ugeth_mii_info *mii_info = ugeth->mii_info; @@ -1722,7 +1708,7 @@ static void adjust_link(struct net_device *dev) if (mii_info->speed != ugeth->oldspeed) { switch (mii_info->speed) { case 1000: -#ifdef CONFIG_MPC836x +#ifdef CONFIG_PPC_MPC836x /* FIXME: This code is for 100Mbs BUG fixing, remove this when it is fixed!!! */ if (ugeth->ug_info->enet_interface == @@ -1768,7 +1754,7 @@ remove this when it is fixed!!! */ break; case 100: case 10: -#ifdef CONFIG_MPC836x +#ifdef CONFIG_PPC_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; @@ -1827,9 +1813,9 @@ remove this lines when it will be fixed!!! */ */ static int init_phy(struct net_device *dev) { - ucc_geth_private_t *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = netdev_priv(dev); struct phy_info *curphy; - ucc_mii_mng_t *mii_regs; + struct ucc_mii_mng *mii_regs; struct ugeth_mii_info *mii_info; int err; @@ -1914,17 +1900,17 @@ static int init_phy(struct net_device *dev) } #ifdef CONFIG_UGETH_TX_ON_DEMOND -static int ugeth_transmit_on_demand(ucc_geth_private_t *ugeth) +static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) { - ucc_fast_transmit_on_demand(ugeth->uccf); + struct ucc_fastransmit_on_demand(ugeth->uccf); return 0; } #endif -static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth) +static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) { - ucc_fast_private_t *uccf; + struct ucc_fast_private *uccf; u32 cecr_subblock; u32 temp; @@ -1940,7 +1926,7 @@ static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth) 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); + QE_CR_PROTOCOL_ETHERNET, 0); /* Wait for command to complete */ do { @@ -1952,9 +1938,9 @@ static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth) return 0; } -static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth) +static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) { - ucc_fast_private_t *uccf; + struct ucc_fast_private *uccf; u32 cecr_subblock; u8 temp; @@ -1973,7 +1959,7 @@ static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth) 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); + QE_CR_PROTOCOL_ETHERNET, 0); temp = ugeth->p_rx_glbl_pram->rxgstpack; } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX)); @@ -1983,41 +1969,40 @@ static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth) return 0; } -static int ugeth_restart_tx(ucc_geth_private_t *ugeth) +static int ugeth_restart_tx(struct ucc_geth_private *ugeth) { - ucc_fast_private_t *uccf; + struct ucc_fast_private *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); + qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); uccf->stopped_tx = 0; return 0; } -static int ugeth_restart_rx(ucc_geth_private_t *ugeth) +static int ugeth_restart_rx(struct ucc_geth_private *ugeth) { - ucc_fast_private_t *uccf; + struct ucc_fast_private *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, + qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); uccf->stopped_rx = 0; return 0; } -static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode) +static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) { - ucc_fast_private_t *uccf; + struct ucc_fast_private *uccf; int enabled_tx, enabled_rx; uccf = ugeth->uccf; @@ -2044,9 +2029,9 @@ static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode) } -static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode) +static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode) { - ucc_fast_private_t *uccf; + struct ucc_fast_private *uccf; uccf = ugeth->uccf; @@ -2069,7 +2054,7 @@ static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode) return 0; } -static void ugeth_dump_regs(ucc_geth_private_t *ugeth) +static void ugeth_dump_regs(struct ucc_geth_private *ugeth) { #ifdef DEBUG ucc_fast_dump_regs(ugeth->uccf); @@ -2079,9 +2064,9 @@ static void ugeth_dump_regs(ucc_geth_private_t *ugeth) } #ifdef CONFIG_UGETH_FILTERING -static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t * +static int ugeth_ext_filtering_serialize_tad(struct ucc_geth_tad_params * p_UccGethTadParams, - qe_fltr_tad_t *qe_fltr_tad) + struct qe_fltr_tad *qe_fltr_tad) { u16 temp; @@ -2119,11 +2104,11 @@ static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t * 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) +static struct enet_addr_container_t + *ugeth_82xx_filtering_get_match_addr_in_hash(struct ucc_geth_private *ugeth, + struct enet_addr *p_enet_addr) { - enet_addr_container_t *enet_addr_cont; + struct enet_addr_container *enet_addr_cont; struct list_head *p_lh; u16 i, num; int32_t j; @@ -2144,7 +2129,7 @@ static enet_addr_container_t for (i = 0; i < num; i++) { enet_addr_cont = - (enet_addr_container_t *) + (struct enet_addr_container *) 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]) @@ -2157,11 +2142,11 @@ static enet_addr_container_t return NULL; } -static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t *ugeth, - enet_addr_t *p_enet_addr) +static int ugeth_82xx_filtering_add_addr_in_hash(struct ucc_geth_private *ugeth, + struct enet_addr *p_enet_addr) { - ucc_geth_enet_address_recognition_location_e location; - enet_addr_container_t *enet_addr_cont; + enum ucc_geth_enet_address_recognition_location location; + struct enet_addr_container *enet_addr_cont; struct list_head *p_lh; u8 i; u32 limit; @@ -2196,18 +2181,17 @@ static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t *ugeth, enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ ++(*p_counter); - hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address)); - + 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) +static int ugeth_82xx_filtering_clear_addr_in_hash(struct ucc_geth_private *ugeth, + struct enet_addr *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; + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; + struct enet_addr_container *enet_addr_cont; + struct ucc_fast_private *uccf; + enum comm_dir comm_dir; u16 i, num; struct list_head *p_lh; u32 *addr_h, *addr_l; @@ -2216,7 +2200,7 @@ static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth, uccf = ugeth->uccf; p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> addressfiltering; if (! @@ -2256,9 +2240,9 @@ static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth, num = --(*p_counter); for (i = 0; i < num; i++) { enet_addr_cont = - (enet_addr_container_t *) + (struct enet_addr_container *) ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); - hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address)); + hw_add_addr_in_hash(ugeth, enet_addr_cont->address); enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ } @@ -2269,14 +2253,14 @@ static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth, } #endif /* CONFIG_UGETH_FILTERING */ -static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t * +static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private * ugeth, - enet_addr_type_e + enum enet_addr_type 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 ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; + struct ucc_fast_private *uccf; + enum comm_dir comm_dir; struct list_head *p_lh; u16 i, num; u32 *addr_h, *addr_l; @@ -2285,7 +2269,7 @@ static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t * uccf = ugeth->uccf; p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> addressfiltering; if (enet_addr_type == ENET_ADDR_TYPE_GROUP) { @@ -2331,8 +2315,8 @@ static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t * } #ifdef CONFIG_UGETH_FILTERING -static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t *ugeth, - enet_addr_t *p_enet_addr, +static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth, + struct enet_addr *p_enet_addr, u8 paddr_num) { int i; @@ -2352,14 +2336,14 @@ static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t *ugeth, } #endif /* CONFIG_UGETH_FILTERING */ -static int ugeth_82xx_filtering_clear_addr_in_paddr(ucc_geth_private_t *ugeth, +static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *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) +static void ucc_geth_memclean(struct ucc_geth_private *ugeth) { u16 i, j; u8 *bd; @@ -2433,8 +2417,8 @@ static void ucc_geth_memclean(ucc_geth_private_t *ugeth) 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) & + ((qe_bd_t *)bd)->buf, + (in_be32((u32 *)bd) & BD_LENGTH_MASK), DMA_TO_DEVICE); dev_kfree_skb_any(ugeth->tx_skbuff[i][j]); @@ -2460,18 +2444,17 @@ static void ucc_geth_memclean(ucc_geth_private_t *ugeth) 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]); + dma_unmap_single(NULL, + ((struct qe_bd *)bd)->buf, + 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; + bd += sizeof(struct qe_bd); } kfree(ugeth->rx_skbuff[i]); @@ -2496,11 +2479,11 @@ static void ucc_geth_memclean(ucc_geth_private_t *ugeth) static void ucc_geth_set_multi(struct net_device *dev) { - ucc_geth_private_t *ugeth; + struct ucc_geth_private *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; + struct ucc_fast *uf_regs; + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; + u8 tempaddr[6]; u8 *mcptr, *tdptr; int i, j; @@ -2517,7 +2500,7 @@ static void ucc_geth_set_multi(struct net_device *dev) uf_regs->upsmr &= ~UPSMR_PRO; p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth-> + (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> p_rx_glbl_pram->addressfiltering; if (dev->flags & IFF_ALLMULTI) { @@ -2546,23 +2529,22 @@ static void ucc_geth_set_multi(struct net_device *dev) * copy bytes MSB first from dmi_addr. */ mcptr = (u8 *) dmi->dmi_addr + 5; - tdptr = (u8 *) & tempaddr; + 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); - + hw_add_addr_in_hash(ugeth, tempaddr); } } } } -static void ucc_geth_stop(ucc_geth_private_t *ugeth) +static void ucc_geth_stop(struct ucc_geth_private *ugeth) { - ucc_geth_t *ug_regs = ugeth->ug_regs; + struct ucc_geth *ug_regs = ugeth->ug_regs; u32 tempval; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -2605,15 +2587,15 @@ static void ucc_geth_stop(ucc_geth_private_t *ugeth) ucc_geth_memclean(ugeth); } -static int ucc_geth_startup(ucc_geth_private_t *ugeth) +static int ucc_geth_startup(struct ucc_geth_private *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; + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; + struct ucc_geth_init_pram *p_init_enet_pram; + struct ucc_fast_private *uccf; + struct ucc_geth_info *ug_info; + struct ucc_fast_info *uf_info; + struct ucc_fast *uf_regs; + struct ucc_geth *ug_regs; int ret_val = -EINVAL; u32 remoder = UCC_GETH_REMODER_INIT; u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; @@ -2788,7 +2770,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); uf_regs = uccf->uf_regs; - ug_regs = (ucc_geth_t *) (uccf->uf_regs); + ug_regs = (struct ucc_geth *) (uccf->uf_regs); ugeth->ug_regs = ug_regs; init_default_reg_vals(&uf_regs->upsmr, @@ -2869,10 +2851,10 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* 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) + length = ((ug_info->bdRingLenTx[j] * sizeof(struct qe_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) % + if ((ug_info->bdRingLenTx[j] * sizeof(struct qe_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) { @@ -2904,13 +2886,13 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } /* 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); + ug_info->bdRingLenTx[j] * sizeof(struct qe_bd), 0, + length - ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)); } /* Allocate Rx bds */ for (j = 0; j < ug_info->numQueuesRx; j++) { - length = ug_info->bdRingLenRx[j] * UCC_GETH_SIZE_OF_BD; + length = ug_info->bdRingLenRx[j] * sizeof(struct qe_bd); if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { u32 align = 4; if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4) @@ -2960,12 +2942,15 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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; + /* clear bd buffer */ + out_be32(&((struct qe_bd *)bd)->buf, 0); + /* set bd status and length */ + out_be32((u32 *)bd, 0); + bd += sizeof(struct qe_bd); } - bd -= UCC_GETH_SIZE_OF_BD; - BD_STATUS_AND_LENGTH_SET(bd, T_W);/* for last BD set Wrap bit */ + bd -= sizeof(struct qe_bd); + /* set bd status and length */ + out_be32((u32 *)bd, T_W); /* for last BD set Wrap bit */ } /* Init Rx bds */ @@ -2989,12 +2974,15 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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; + /* set bd status and length */ + out_be32((u32 *)bd, R_I); + /* clear bd buffer */ + out_be32(&((struct qe_bd *)bd)->buf, 0); + bd += sizeof(struct qe_bd); } - bd -= UCC_GETH_SIZE_OF_BD; - BD_STATUS_AND_LENGTH_SET(bd, R_W);/* for last BD set Wrap bit */ + bd -= sizeof(struct qe_bd); + /* set bd status and length */ + out_be32((u32 *)bd, R_W); /* for last BD set Wrap bit */ } /* @@ -3003,7 +2991,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* Tx global PRAM */ /* Allocate global tx parameter RAM page */ ugeth->tx_glbl_pram_offset = - qe_muram_alloc(sizeof(ucc_geth_tx_global_pram_t), + qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram), UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT); if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) { ugeth_err @@ -3013,10 +3001,10 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) return -ENOMEM; } ugeth->p_tx_glbl_pram = - (ucc_geth_tx_global_pram_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_tx_global_pram *) 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)); + memset(ugeth->p_tx_glbl_pram, 0, sizeof(struct ucc_geth_tx_global_pram)); /* Fill global PRAM */ @@ -3024,7 +3012,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* Size varies with number of Tx threads */ ugeth->thread_dat_tx_offset = qe_muram_alloc(numThreadsTxNumerical * - sizeof(ucc_geth_thread_data_tx_t) + + sizeof(struct ucc_geth_thread_data_tx) + 32 * (numThreadsTxNumerical == 1), UCC_GETH_THREAD_DATA_ALIGNMENT); if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) { @@ -3036,7 +3024,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_thread_data_tx = - (ucc_geth_thread_data_tx_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_thread_data_tx *) qe_muram_addr(ugeth-> thread_dat_tx_offset); out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset); @@ -3053,7 +3041,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* 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), + sizeof(struct ucc_geth_send_queue_qd), UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) { ugeth_err @@ -3064,7 +3052,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_send_q_mem_reg = - (ucc_geth_send_queue_mem_region_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_send_queue_mem_region *) qe_muram_addr(ugeth-> send_q_mem_reg_offset); out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset); @@ -3073,7 +3061,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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; + 1) * sizeof(struct qe_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])); @@ -3096,7 +3084,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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), + qe_muram_alloc(sizeof(struct ucc_geth_scheduler), UCC_GETH_SCHEDULER_ALIGNMENT); if (IS_MURAM_ERR(ugeth->scheduler_offset)) { ugeth_err @@ -3107,12 +3095,12 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_scheduler = - (ucc_geth_scheduler_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_scheduler *) 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)); + memset(ugeth->p_scheduler, 0, sizeof(struct ucc_geth_scheduler)); /* Set values in scheduler */ out_be32(&ugeth->p_scheduler->mblinterval, @@ -3144,7 +3132,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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), + (struct ucc_geth_tx_firmware_statistics_pram), UCC_GETH_TX_STATISTICS_ALIGNMENT); if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) { ugeth_err @@ -3154,11 +3142,11 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) return -ENOMEM; } ugeth->p_tx_fw_statistics_pram = - (ucc_geth_tx_firmware_statistics_pram_t *) + (struct ucc_geth_tx_firmware_statistics_pram *) 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)); + 0, sizeof(struct ucc_geth_tx_firmware_statistics_pram)); } /* temoder */ @@ -3183,7 +3171,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* Rx global PRAM */ /* Allocate global rx parameter RAM page */ ugeth->rx_glbl_pram_offset = - qe_muram_alloc(sizeof(ucc_geth_rx_global_pram_t), + qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram), UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT); if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) { ugeth_err @@ -3193,10 +3181,10 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) return -ENOMEM; } ugeth->p_rx_glbl_pram = - (ucc_geth_rx_global_pram_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_rx_global_pram *) 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)); + memset(ugeth->p_rx_glbl_pram, 0, sizeof(struct ucc_geth_rx_global_pram)); /* Fill global PRAM */ @@ -3204,7 +3192,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* Size varies with number of Rx threads */ ugeth->thread_dat_rx_offset = qe_muram_alloc(numThreadsRxNumerical * - sizeof(ucc_geth_thread_data_rx_t), + sizeof(struct ucc_geth_thread_data_rx), UCC_GETH_THREAD_DATA_ALIGNMENT); if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) { ugeth_err @@ -3215,7 +3203,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_thread_data_rx = - (ucc_geth_thread_data_rx_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_thread_data_rx *) qe_muram_addr(ugeth-> thread_dat_rx_offset); out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset); @@ -3227,7 +3215,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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), + (struct ucc_geth_rx_firmware_statistics_pram), UCC_GETH_RX_STATISTICS_ALIGNMENT); if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) { ugeth_err @@ -3237,11 +3225,11 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) return -ENOMEM; } ugeth->p_rx_fw_statistics_pram = - (ucc_geth_rx_firmware_statistics_pram_t *) + (struct ucc_geth_rx_firmware_statistics_pram *) 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)); + sizeof(struct ucc_geth_rx_firmware_statistics_pram)); } /* intCoalescingPtr */ @@ -3249,7 +3237,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* 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), + sizeof(struct ucc_geth_rx_interrupt_coalescing_entry), UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { ugeth_err @@ -3260,7 +3248,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_rx_irq_coalescing_tbl = - (ucc_geth_rx_interrupt_coalescing_table_t *) + (struct ucc_geth_rx_interrupt_coalescing_table *) qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset); out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr, ugeth->rx_irq_coalescing_tbl_offset); @@ -3300,7 +3288,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) 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); + out_be32(&ugeth->p_rx_glbl_pram->l3qt[j/8], l3qt); } /* vlantype */ @@ -3316,8 +3304,8 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* 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)), + (sizeof(struct ucc_geth_rx_bd_queues_entry) + + sizeof(struct ucc_geth_rx_prefetched_bds)), UCC_GETH_RX_BD_QUEUES_ALIGNMENT); if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) { ugeth_err @@ -3328,14 +3316,14 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_rx_bd_qs_tbl = - (ucc_geth_rx_bd_queues_entry_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_rx_bd_queues_entry *) 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))); + ug_info->numQueuesRx * (sizeof(struct ucc_geth_rx_bd_queues_entry) + + sizeof(struct ucc_geth_rx_prefetched_bds))); /* Setup the table */ /* Assume BD rings are already established */ @@ -3406,7 +3394,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* Allocate memory for extended filtering Mode Global Parameters */ ugeth->exf_glbl_param_offset = - qe_muram_alloc(sizeof(ucc_geth_exf_global_pram_t), + qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram), UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT); if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) { ugeth_err @@ -3417,7 +3405,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_exf_glbl_param = - (ucc_geth_exf_global_pram_t *) qe_muram_addr(ugeth-> + (struct ucc_geth_exf_global_pram *) qe_muram_addr(ugeth-> exf_glbl_param_offset); out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam, ugeth->exf_glbl_param_offset); @@ -3439,7 +3427,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) INIT_LIST_HEAD(&ugeth->ind_hash_q); } p_82xx_addr_filt = - (ucc_geth_82xx_address_filtering_pram_t *) ugeth-> + (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> p_rx_glbl_pram->addressfiltering; ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, @@ -3462,7 +3450,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) * 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), + (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) { ugeth_err ("%s: Can not allocate memory for" @@ -3472,7 +3460,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } /* Zero out *p_init_enet_param_shadow */ memset((char *)ugeth->p_init_enet_param_shadow, - 0, sizeof(ucc_geth_init_pram_t)); + 0, sizeof(struct ucc_geth_init_pram)); /* Fill shadow InitEnet command parameter structure */ @@ -3506,7 +3494,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } ugeth->p_init_enet_param_shadow->largestexternallookupkeysize = ug_info->largestexternallookupkeysize; - size = sizeof(ucc_geth_thread_rx_pram_t); + size = sizeof(struct ucc_geth_thread_rx_pram); if (ug_info->rxExtendedFiltering) { size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; if (ug_info->largestexternallookupkeysize == @@ -3537,7 +3525,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) fill_init_enet_entries(ugeth, &(ugeth->p_init_enet_param_shadow-> txthread[0]), numThreadsTxNumerical, - sizeof(ucc_geth_thread_tx_pram_t), + sizeof(struct ucc_geth_thread_tx_pram), UCC_GETH_THREAD_TX_PRAM_ALIGNMENT, ug_info->riscTx, 0)) != 0) { ugeth_err("%s: Can not fill p_init_enet_param_shadow.", @@ -3557,7 +3545,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) } /* Allocate InitEnet command parameter structure */ - init_enet_pram_offset = qe_muram_alloc(sizeof(ucc_geth_init_pram_t), 4); + init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4); if (IS_MURAM_ERR(init_enet_pram_offset)) { ugeth_err ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", @@ -3566,7 +3554,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) return -ENOMEM; } p_init_enet_pram = - (ucc_geth_init_pram_t *) qe_muram_addr(init_enet_pram_offset); + (struct ucc_geth_init_pram *) 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; @@ -3591,7 +3579,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* 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, + qe_issue_cmd(command, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, init_enet_pram_offset); /* Free InitEnet command parameter */ @@ -3603,7 +3591,7 @@ static int ucc_geth_startup(ucc_geth_private_t *ugeth) /* 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); + struct ucc_geth_private *ugeth = netdev_priv(dev); return &(ugeth->stats); } @@ -3614,7 +3602,7 @@ static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev) * starting over will fix the problem. */ static void ucc_geth_timeout(struct net_device *dev) { - ucc_geth_private_t *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = netdev_priv(dev); ugeth_vdbg("%s: IN", __FUNCTION__); @@ -3634,7 +3622,7 @@ static void ucc_geth_timeout(struct net_device *dev) /* 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); + struct ucc_geth_private *ugeth = netdev_priv(dev); u8 *bd; /* BD pointer */ u32 bd_status; u8 txQ = 0; @@ -3647,7 +3635,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Start from the next BD that should be filled */ bd = ugeth->txBd[txQ]; - bd_status = BD_STATUS_AND_LENGTH(bd); + bd_status = in_be32((u32 *)bd); /* Save the skb pointer so we can free it later */ ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb; @@ -3657,20 +3645,21 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); /* set up the buffer descriptor */ - BD_BUFFER_SET(bd, + out_be32(&((struct qe_bd *)bd)->buf, dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE)); - //printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); + /* 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); + /* set bd status and length */ + out_be32((u32 *)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; + ugeth->txBd[txQ] = bd + sizeof(struct qe_bd); else ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ]; @@ -3695,7 +3684,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit) +static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit) { struct sk_buff *skb; u8 *bd; @@ -3709,11 +3698,11 @@ static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit) /* collect received buffers */ bd = ugeth->rxBd[rxQ]; - bd_status = BD_STATUS_AND_LENGTH(bd); + bd_status = in_be32((u32 *)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); + bdBuffer = (u8 *) in_be32(&((struct qe_bd *)bd)->buf); length = (u16) ((bd_status & BD_LENGTH_MASK) - 4); skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]]; @@ -3768,9 +3757,9 @@ static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit) if (bd_status & R_W) bd = ugeth->p_rx_bd_ring[rxQ]; else - bd += UCC_GETH_SIZE_OF_BD; + bd += sizeof(struct qe_bd); - bd_status = BD_STATUS_AND_LENGTH(bd); + bd_status = in_be32((u32 *)bd); } ugeth->rxBd[rxQ] = bd; @@ -3781,12 +3770,12 @@ static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit) 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); + struct ucc_geth_private *ugeth = netdev_priv(dev); u8 *bd; /* BD pointer */ u32 bd_status; bd = ugeth->confBd[txQ]; - bd_status = BD_STATUS_AND_LENGTH(bd); + bd_status = in_be32((u32 *)bd); /* Normal processing. */ while ((bd_status & T_R) == 0) { @@ -3813,7 +3802,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Advance the confirmation BD pointer */ if (!(bd_status & T_W)) - ugeth->confBd[txQ] += UCC_GETH_SIZE_OF_BD; + ugeth->confBd[txQ] += sizeof(struct qe_bd); else ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ]; } @@ -3823,7 +3812,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) #ifdef CONFIG_UGETH_NAPI static int ucc_geth_poll(struct net_device *dev, int *budget) { - ucc_geth_private_t *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = netdev_priv(dev); int howmany; int rx_work_limit = *budget; u8 rxQ = 0; @@ -3847,9 +3836,9 @@ static int ucc_geth_poll(struct net_device *dev, int *budget) static irqreturn_t ucc_geth_irq_handler(int irq, void *info) { 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; + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_fast_private *uccf; + struct ucc_geth_info *ug_info; register u32 ucce = 0; register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; @@ -3912,7 +3901,7 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) static irqreturn_t phy_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; - ucc_geth_private_t *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = netdev_priv(dev); ugeth_vdbg("%s: IN", __FUNCTION__); @@ -3932,8 +3921,8 @@ static irqreturn_t phy_interrupt(int irq, void *dev_id) 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; + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_geth *ug_regs; int result = 0; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -3963,7 +3952,7 @@ static void ugeth_phy_change(void *data) static void ugeth_phy_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - ucc_geth_private_t *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = netdev_priv(dev); schedule_work(&ugeth->tq); @@ -3979,7 +3968,7 @@ static void ugeth_phy_timer(unsigned long data) 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); + struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev); static int secondary = UGETH_AN_TIMEOUT; int result; @@ -4034,7 +4023,7 @@ static void ugeth_phy_startup_timer(unsigned long data) /* Returns 0 for success. */ static int ucc_geth_open(struct net_device *dev) { - ucc_geth_private_t *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = netdev_priv(dev); int err; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -4111,7 +4100,7 @@ static int ucc_geth_open(struct net_device *dev) /* 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); + struct ucc_geth_private *ugeth = netdev_priv(dev); ugeth_vdbg("%s: IN", __FUNCTION__); @@ -4130,30 +4119,53 @@ static int ucc_geth_close(struct net_device *dev) const struct ethtool_ops ucc_geth_ethtool_ops = { }; -static int ucc_geth_probe(struct device *device) +static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) { - struct platform_device *pdev = to_platform_device(device); - struct ucc_geth_platform_data *ugeth_pdata; + struct device *device = &ofdev->dev; + struct device_node *np = ofdev->node; struct net_device *dev = NULL; struct ucc_geth_private *ugeth = NULL; struct ucc_geth_info *ug_info; - int err; + struct resource res; + struct device_node *phy; + int err, ucc_num, phy_interface; static int mii_mng_configured = 0; + const phandle *ph; + const unsigned int *prop; ugeth_vdbg("%s: IN", __FUNCTION__); - ugeth_pdata = (struct ucc_geth_platform_data *)pdev->dev.platform_data; + prop = get_property(np, "device-id", NULL); + ucc_num = *prop - 1; + if ((ucc_num < 0) || (ucc_num > 7)) + return -ENODEV; + + ug_info = &ugeth_info[ucc_num]; + ug_info->uf_info.ucc_num = ucc_num; + prop = get_property(np, "rx-clock", NULL); + ug_info->uf_info.rx_clock = *prop; + prop = get_property(np, "tx-clock", NULL); + ug_info->uf_info.tx_clock = *prop; + err = of_address_to_resource(np, 0, &res); + if (err) + return -EINVAL; + + ug_info->uf_info.regs = res.start; + ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); + + ph = get_property(np, "phy-handle", NULL); + phy = of_find_node_by_phandle(*ph); - 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; + if (phy == NULL) + return -ENODEV; + + prop = get_property(phy, "reg", NULL); + ug_info->phy_address = *prop; + prop = get_property(phy, "interface", NULL); + ug_info->enet_interface = *prop; + ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0); + ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)? + 0:FSL_UGETH_BRD_HAS_PHY_INTR; 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, @@ -4161,12 +4173,44 @@ static int ucc_geth_probe(struct device *device) if (ug_info == NULL) { ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__, - pdev->id); + ucc_num); return -ENODEV; } + /* FIXME: Work around for early chip rev. */ + /* There's a bug in initial chip rev(s) in the RGMII ac */ + /* timing. */ + /* The following compensates by writing to the reserved */ + /* QE Port Output Hold Registers (CPOH1?). */ + prop = get_property(phy, "interface", NULL); + phy_interface = *prop; + if ((phy_interface == ENET_1000_RGMII) || + (phy_interface == ENET_100_RGMII) || + (phy_interface == ENET_10_RGMII)) { + struct device_node *soc; + phys_addr_t immrbase = -1; + u32 *tmp_reg; + u32 tmp_val; + + soc = of_find_node_by_type(NULL, "soc"); + if (soc) { + unsigned int size; + const void *prop = get_property(soc, "reg", &size); + immrbase = of_translate_address(soc, prop); + of_node_put(soc); + }; + + tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4); + tmp_val = in_be32(tmp_reg); + if (ucc_num == 1) + out_be32(tmp_reg, tmp_val | 0x00003000); + else if (ucc_num == 2) + out_be32(tmp_reg, tmp_val | 0x0c000000); + iounmap(tmp_reg); + } + if (!mii_mng_configured) { - ucc_set_qe_mux_mii_mng(ug_info->uf_info.ucc_num); + ucc_set_qe_mux_mii_mng(ucc_num); mii_mng_configured = 1; } @@ -4213,13 +4257,14 @@ static int ucc_geth_probe(struct device *device) ugeth->ug_info = ug_info; ugeth->dev = dev; - memcpy(dev->dev_addr, ugeth_pdata->mac_addr, 6); + memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6); return 0; } -static int ucc_geth_remove(struct device *device) +static int ucc_geth_remove(struct of_device* ofdev) { + struct device *device = &ofdev->dev; struct net_device *dev = dev_get_drvdata(device); struct ucc_geth_private *ugeth = netdev_priv(dev); @@ -4230,28 +4275,38 @@ static int ucc_geth_remove(struct device *device) 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 struct of_device_id ucc_geth_match[] = { + { + .type = "network", + .compatible = "ucc_geth", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, ucc_geth_match); + +static struct of_platform_driver ucc_geth_driver = { + .name = DRV_NAME, + .match_table = ucc_geth_match, + .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); + return of_register_driver(&ucc_geth_driver); } static void __exit ucc_geth_exit(void) { - driver_unregister(&ucc_geth_driver); + of_unregister_driver(&ucc_geth_driver); } module_init(ucc_geth_init); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 005965f5dd9..a6656125359 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -36,24 +36,24 @@ #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 -typedef struct ucc_mii_mng { +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; +} __attribute__ ((packed)); -typedef struct ucc_geth { - ucc_fast_t uccf; +struct ucc_geth { + struct ucc_fast 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 */ + struct ucc_mii_mng miimng; /* MII management structure */ u32 ifctl; /* interface control reg */ u32 ifstat; /* interface statux reg */ u32 macstnaddr1; /* mac station address part 1 reg */ @@ -111,7 +111,7 @@ typedef struct ucc_geth { u32 scar; /* Statistics carry register */ u32 scam; /* Statistics caryy mask register */ u8 res5[0x200 - 0x1c4]; -} __attribute__ ((packed)) ucc_geth_t; +} __attribute__ ((packed)); /* UCC GETH TEMODR Register */ #define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics @@ -508,39 +508,39 @@ typedef struct ucc_geth { /* UCC GETH UDSR (Data Synchronization Register) */ #define UDSR_MAGIC 0x067E -typedef struct ucc_geth_thread_data_tx { +struct ucc_geth_thread_data_tx { u8 res0[104]; -} __attribute__ ((packed)) ucc_geth_thread_data_tx_t; +} __attribute__ ((packed)); -typedef struct ucc_geth_thread_data_rx { +struct ucc_geth_thread_data_rx { u8 res0[40]; -} __attribute__ ((packed)) ucc_geth_thread_data_rx_t; +} __attribute__ ((packed)); /* Send Queue Queue-Descriptor */ -typedef struct ucc_geth_send_queue_qd { +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; +} __attribute__ ((packed)); -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; +struct ucc_geth_send_queue_mem_region { + struct ucc_geth_send_queue_qd sqqd[NUM_TX_QUEUES]; +} __attribute__ ((packed)); -typedef struct ucc_geth_thread_tx_pram { +struct ucc_geth_thread_tx_pram { u8 res0[64]; -} __attribute__ ((packed)) ucc_geth_thread_tx_pram_t; +} __attribute__ ((packed)); -typedef struct ucc_geth_thread_rx_pram { +struct ucc_geth_thread_rx_pram { u8 res0[128]; -} __attribute__ ((packed)) ucc_geth_thread_rx_pram_t; +} __attribute__ ((packed)); #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 { +struct ucc_geth_scheduler { u16 cpucount0; /* CPU packet counter */ u16 cpucount1; /* CPU packet counter */ u16 cecount0; /* QE packet counter */ @@ -574,9 +574,9 @@ typedef struct ucc_geth_scheduler { /**< weight factor for queues */ u32 minw; /* temporary variable handled by QE */ u8 res1[0x70 - 0x64]; -} __attribute__ ((packed)) ucc_geth_scheduler_t; +} __attribute__ ((packed)); -typedef struct ucc_geth_tx_firmware_statistics_pram { +struct ucc_geth_tx_firmware_statistics_pram { u32 sicoltx; /* single collision */ u32 mulcoltx; /* multiple collision */ u32 latecoltxfr; /* late collision */ @@ -596,9 +596,9 @@ typedef struct ucc_geth_tx_firmware_statistics_pram { and 1518 octets */ u32 txpktsjumbo; /* total packets (including bad) between 1024 and MAXLength octets */ -} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_pram_t; +} __attribute__ ((packed)); -typedef struct ucc_geth_rx_firmware_statistics_pram { +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 */ @@ -630,33 +630,33 @@ typedef struct ucc_geth_rx_firmware_statistics_pram { replaced */ u32 insertvlan; /* total frames that had their VLAN tag inserted */ -} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_pram_t; +} __attribute__ ((packed)); -typedef struct ucc_geth_rx_interrupt_coalescing_entry { +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; +} __attribute__ ((packed)); -typedef struct ucc_geth_rx_interrupt_coalescing_table { - ucc_geth_rx_interrupt_coalescing_entry_t coalescingentry[NUM_RX_QUEUES]; +struct ucc_geth_rx_interrupt_coalescing_table { + struct ucc_geth_rx_interrupt_coalescing_entry coalescingentry[NUM_RX_QUEUES]; /**< interrupt coalescing entry */ -} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_table_t; +} __attribute__ ((packed)); -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; +struct ucc_geth_rx_prefetched_bds { + struct qe_bd bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */ +} __attribute__ ((packed)); -typedef struct ucc_geth_rx_bd_queues_entry { +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; +} __attribute__ ((packed)); -typedef struct ucc_geth_tx_global_pram { +struct ucc_geth_tx_global_pram { u16 temoder; u8 res0[0x38 - 0x02]; u32 sqptr; /* a base pointer to send queue memory region */ @@ -670,15 +670,15 @@ typedef struct ucc_geth_tx_global_pram { u32 tqptr; /* a base pointer to the Tx Queues Memory Region */ u8 res2[0x80 - 0x74]; -} __attribute__ ((packed)) ucc_geth_tx_global_pram_t; +} __attribute__ ((packed)); /* structure representing Extended Filtering Global Parameters in PRAM */ -typedef struct ucc_geth_exf_global_pram { +struct ucc_geth_exf_global_pram { u32 l2pcdptr; /* individual address filter, high */ u8 res0[0x10 - 0x04]; -} __attribute__ ((packed)) ucc_geth_exf_global_pram_t; +} __attribute__ ((packed)); -typedef struct ucc_geth_rx_global_pram { +struct ucc_geth_rx_global_pram { u32 remoder; /* ethernet mode reg. */ u32 rqptr; /* base pointer to the Rx Queues Memory Region*/ u32 res0[0x1]; @@ -710,12 +710,12 @@ typedef struct ucc_geth_rx_global_pram { u32 exfGlobalParam; /* base address for extended filtering global parameters */ u8 res6[0x100 - 0xC4]; /* Initialize to zero */ -} __attribute__ ((packed)) ucc_geth_rx_global_pram_t; +} __attribute__ ((packed)); #define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01 /* structure representing InitEnet command */ -typedef struct ucc_geth_init_pram { +struct ucc_geth_init_pram { u8 resinit1; u8 resinit2; u8 resinit3; @@ -729,7 +729,7 @@ typedef struct ucc_geth_init_pram { u32 txglobal; /* tx global */ u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */ u8 res3[0x1]; -} __attribute__ ((packed)) ucc_geth_init_pram_t; +} __attribute__ ((packed)); #define ENET_INIT_PARAM_RGF_SHIFT (32 - 4) #define ENET_INIT_PARAM_TGF_SHIFT (32 - 8) @@ -746,27 +746,27 @@ typedef struct ucc_geth_init_pram { #define ENET_INIT_PARAM_MAGIC_RES_INIT5 0x0400 /* structure representing 82xx Address Filtering Enet Address in PRAM */ -typedef struct ucc_geth_82xx_enet_address { +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; +} __attribute__ ((packed)); /* structure representing 82xx Address Filtering PRAM */ -typedef struct ucc_geth_82xx_address_filtering_pram { +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]; + struct ucc_geth_82xx_enet_address taddr; + struct ucc_geth_82xx_enet_address paddr[NUM_OF_PADDRS]; u8 res0[0x40 - 0x38]; -} __attribute__ ((packed)) ucc_geth_82xx_address_filtering_pram_t; +} __attribute__ ((packed)); /* GETH Tx firmware statistics structure, used when calling UCC_GETH_GetStatistics. */ -typedef struct ucc_geth_tx_firmware_statistics { +struct ucc_geth_tx_firmware_statistics { u32 sicoltx; /* single collision */ u32 mulcoltx; /* multiple collision */ u32 latecoltxfr; /* late collision */ @@ -786,11 +786,11 @@ typedef struct ucc_geth_tx_firmware_statistics { and 1518 octets */ u32 txpktsjumbo; /* total packets (including bad) between 1024 and MAXLength octets */ -} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_t; +} __attribute__ ((packed)); /* GETH Rx firmware statistics structure, used when calling UCC_GETH_GetStatistics. */ -typedef struct ucc_geth_rx_firmware_statistics { +struct ucc_geth_rx_firmware_statistics { u32 frrxfcser; /* frames with crc error */ u32 fraligner; /* frames with alignment error */ u32 inrangelenrxer; /* in range length error */ @@ -822,11 +822,11 @@ typedef struct ucc_geth_rx_firmware_statistics { replaced */ u32 insertvlan; /* total frames that had their VLAN tag inserted */ -} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_t; +} __attribute__ ((packed)); /* GETH hardware statistics structure, used when calling UCC_GETH_GetStatistics. */ -typedef struct ucc_geth_hardware_statistics { +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 @@ -871,7 +871,7 @@ typedef struct ucc_geth_hardware_statistics { u32 rbca; /* Total number of frames received succesfully that had destination address equal to the broadcast address */ -} __attribute__ ((packed)) ucc_geth_hardware_statistics_t; +} __attribute__ ((packed)); /* UCC GETH Tx errors returned via TxConf callback */ #define TX_ERRORS_DEF 0x0200 @@ -1013,21 +1013,21 @@ typedef struct ucc_geth_hardware_statistics { (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) /* Ethernet speed */ -typedef enum enet_speed { +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 { +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 { +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 ) */ @@ -1040,10 +1040,10 @@ typedef enum enet_tbi_mii_reg { 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 { +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 @@ -1065,10 +1065,10 @@ typedef enum ucc_geth_enet_address_recognition_location { 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 { +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 */ @@ -1076,18 +1076,18 @@ typedef enum ucc_geth_vlan_operation_tagged { = 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 { +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 { +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 @@ -1097,11 +1097,11 @@ typedef enum ucc_geth_qos_mode { 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 { +enum ucc_geth_statistics_gathering_mode { UCC_GETH_STATISTICS_GATHERING_MODE_NONE = 0x00000000, /* No statistics gathering */ @@ -1122,10 +1122,10 @@ typedef enum ucc_geth_statistics_gathering_mode { 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 { +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 @@ -1135,61 +1135,59 @@ typedef enum ucc_geth_maccfg2_pad_and_crc_mode { 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 { +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 { +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 { +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 +struct enet_addr_container { + u8 address[ENET_NUM_OCTETS_PER_ADDRESS]; /* ethernet address */ + enum ucc_geth_enet_address_recognition_location 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) +#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr, struct enet_addr_container, node) /* UCC GETH Termination Action Descriptor (TAD) structure. */ -typedef struct ucc_geth_tad_params { +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; + enum ucc_geth_vlan_operation_tagged vtag_op; + enum ucc_geth_vlan_operation_non_tagged vnontag_op; + enum ucc_geth_qos_mode 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; +struct ucc_geth_info { + struct ucc_fast_info uf_info; u8 numQueuesTx; u8 numQueuesRx; int ipCheckSumCheck; @@ -1251,51 +1249,51 @@ typedef struct ucc_geth_info { 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 + enum enet_interface enet_interface; + enum ucc_geth_num_of_station_addresses numStationAddresses; + enum qe_fltr_largest_external_tbl_lookup_key_size 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; + enum ucc_geth_statistics_gathering_mode statisticsMode; + enum ucc_geth_vlan_operation_tagged vlanOperationTagged; + enum ucc_geth_vlan_operation_non_tagged vlanOperationNonTagged; + enum ucc_geth_qos_mode rxQoSMode; + enum ucc_geth_flow_control_mode aufc; + enum ucc_geth_maccfg2_pad_and_crc_mode padAndCrc; + enum ucc_geth_num_of_threads numThreadsTx; + enum ucc_geth_num_of_threads numThreadsRx; + enum qe_risc_allocation riscTx; + enum qe_risc_allocation riscRx; +}; /* structure representing UCC GETH */ -typedef struct ucc_geth_private { - ucc_geth_info_t *ug_info; - ucc_fast_private_t *uccf; +struct ucc_geth_private { + struct ucc_geth_info *ug_info; + struct ucc_fast_private *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; + struct ucc_geth *ug_regs; + struct ucc_geth_init_pram *p_init_enet_param_shadow; + struct ucc_geth_exf_global_pram *p_exf_glbl_param; u32 exf_glbl_param_offset; - ucc_geth_rx_global_pram_t *p_rx_glbl_pram; + struct ucc_geth_rx_global_pram *p_rx_glbl_pram; u32 rx_glbl_pram_offset; - ucc_geth_tx_global_pram_t *p_tx_glbl_pram; + struct ucc_geth_tx_global_pram *p_tx_glbl_pram; u32 tx_glbl_pram_offset; - ucc_geth_send_queue_mem_region_t *p_send_q_mem_reg; + struct ucc_geth_send_queue_mem_region *p_send_q_mem_reg; u32 send_q_mem_reg_offset; - ucc_geth_thread_data_tx_t *p_thread_data_tx; + struct ucc_geth_thread_data_tx *p_thread_data_tx; u32 thread_dat_tx_offset; - ucc_geth_thread_data_rx_t *p_thread_data_rx; + struct ucc_geth_thread_data_rx *p_thread_data_rx; u32 thread_dat_rx_offset; - ucc_geth_scheduler_t *p_scheduler; + struct ucc_geth_scheduler *p_scheduler; u32 scheduler_offset; - ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram; + struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram; u32 tx_fw_statistics_pram_offset; - ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram; + struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram; u32 rx_fw_statistics_pram_offset; - ucc_geth_rx_interrupt_coalescing_table_t *p_rx_irq_coalescing_tbl; + struct ucc_geth_rx_interrupt_coalescing_table *p_rx_irq_coalescing_tbl; u32 rx_irq_coalescing_tbl_offset; - ucc_geth_rx_bd_queues_entry_t *p_rx_bd_qs_tbl; + struct ucc_geth_rx_bd_queues_entry *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]; @@ -1308,7 +1306,7 @@ typedef struct ucc_geth_private { 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 paddr[NUM_OF_PADDRS][ENET_NUM_OCTETS_PER_ADDRESS]; /* ethernet address */ u8 numGroupAddrInHash; u8 numIndAddrInHash; u8 numIndAddrInReg; @@ -1334,6 +1332,6 @@ typedef struct ucc_geth_private { 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 index 67260eb3188..5360ec05eaa 100644 --- a/drivers/net/ucc_geth_phy.c +++ b/drivers/net/ucc_geth_phy.c @@ -42,7 +42,6 @@ #include "ucc_geth.h" #include "ucc_geth_phy.h" -#include <platforms/83xx/mpc8360e_pb.h> #define ugphy_printk(level, format, arg...) \ printk(level format "\n", ## arg) @@ -72,16 +71,14 @@ 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; + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_mii_mng *mii_regs; + enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; u32 tmp_reg; ugphy_vdbg("%s: IN", __FUNCTION__); @@ -116,9 +113,9 @@ void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) /* 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; + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_mii_mng *mii_regs; + enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; u32 tmp_reg; u16 value; @@ -634,11 +631,6 @@ static void dm9161_close(struct ugeth_mii_info *mii_info) 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 */ @@ -650,12 +642,6 @@ Remove this from here when it's fixed */ 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) diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h index 2f98b8f1bb0..f5740783670 100644 --- a/drivers/net/ucc_geth_phy.h +++ b/drivers/net/ucc_geth_phy.h @@ -126,7 +126,7 @@ struct ugeth_mii_info { /* And management functions */ struct phy_info *phyinfo; - ucc_mii_mng_t *mii_regs; + struct ucc_mii_mng *mii_regs; /* forced speed & duplex (no autoneg) * partner speed & duplex & pause (autoneg) diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 58b7efbb075..b5d0d7fb647 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -127,7 +127,7 @@ config LANMEDIA # There is no way to detect a Sealevel board. Force it modular config SEALEVEL_4021 tristate "Sealevel Systems 4021 support" - depends on WAN && ISA && m && ISA_DMA_API + depends on WAN && ISA && m && ISA_DMA_API && INET help This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index dcf46add3ad..5c322dfb79f 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -500,7 +500,7 @@ static int __init n2_init(void) #ifdef MODULE printk(KERN_INFO "n2: no card initialized\n"); #endif - return -ENOSYS; /* no parameters specified, abort */ + return -EINVAL; /* no parameters specified, abort */ } printk(KERN_INFO "%s\n", version); @@ -538,11 +538,11 @@ static int __init n2_init(void) n2_run(io, irq, ram, valid[0], valid[1]); if (*hw == '\x0') - return first_card ? 0 : -ENOSYS; + return first_card ? 0 : -EINVAL; }while(*hw++ == ':'); printk(KERN_ERR "n2: invalid hardware parameters\n"); - return first_card ? 0 : -ENOSYS; + return first_card ? 0 : -EINVAL; } diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 5823e3bca17..36d1c3ff707 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -2867,7 +2867,6 @@ static int ch_config(pc300dev_t * d) uclong clktype = chan->conf.phys_settings.clock_type; ucshort encoding = chan->conf.proto_settings.encoding; ucshort parity = chan->conf.proto_settings.parity; - int tmc, br; ucchar md0, md2; /* Reset the channel */ @@ -2940,8 +2939,12 @@ static int ch_config(pc300dev_t * d) case PC300_RSV: case PC300_X21: if (clktype == CLOCK_INT || clktype == CLOCK_TXINT) { + int tmc, br; + /* Calculate the clkrate parameters */ tmc = clock_rate_calc(clkrate, card->hw.clock, &br); + if (tmc < 0) + return -EIO; cpc_writeb(scabase + M_REG(TMCT, ch), tmc); cpc_writeb(scabase + M_REG(TXS, ch), (TXS_DTRXC | TXS_IBRG | br)); @@ -3097,14 +3100,16 @@ static int cpc_attach(struct net_device *dev, unsigned short encoding, return 0; } -static void cpc_opench(pc300dev_t * d) +static int cpc_opench(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - int ch = chan->channel; + int ch = chan->channel, rc; void __iomem *scabase = card->hw.scabase; - ch_config(d); + rc = ch_config(d); + if (rc) + return rc; rx_config(d); @@ -3113,6 +3118,8 @@ static void cpc_opench(pc300dev_t * d) /* Assert RTS and DTR */ cpc_writeb(scabase + M_REG(CTL, ch), cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR)); + + return 0; } static void cpc_closech(pc300dev_t * d) @@ -3168,9 +3175,16 @@ int cpc_open(struct net_device *dev) } sprintf(ifr.ifr_name, "%s", dev->name); - cpc_opench(d); + result = cpc_opench(d); + if (result) + goto err_out; + netif_start_queue(dev); return 0; + +err_out: + hdlc_close(dev); + return result; } static int cpc_close(struct net_device *dev) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 0a33c8a56e1..efcdaf1c5f7 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2897,6 +2897,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, goto err_out_map; } ai->wifidev = init_wifidev(ai, dev); + if (!ai->wifidev) + goto err_out_reg; set_bit(FLAG_REGISTERED,&ai->flags); airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", @@ -2908,11 +2910,18 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, for( i = 0; i < MAX_FIDS; i++ ) ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); - setup_proc_entry( dev, dev->priv ); /* XXX check for failure */ + if (setup_proc_entry(dev, dev->priv) < 0) + goto err_out_wifi; + netif_start_queue(dev); SET_MODULE_OWNER(dev); return dev; +err_out_wifi: + unregister_netdev(ai->wifidev); + free_netdev(ai->wifidev); +err_out_reg: + unregister_netdev(dev); err_out_map: if (test_bit(FLAG_MPI,&ai->flags) && pci) { pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma); @@ -3089,7 +3098,8 @@ static int airo_thread(void *data) { set_bit(JOB_AUTOWEP, &ai->jobs); break; } - if (!kthread_should_stop()) { + if (!kthread_should_stop() && + !freezing(current)) { unsigned long wake_at; if (!ai->expires || !ai->scan_timeout) { wake_at = max(ai->expires, @@ -3101,7 +3111,8 @@ static int airo_thread(void *data) { schedule_timeout(wake_at - jiffies); continue; } - } else if (!kthread_should_stop()) { + } else if (!kthread_should_stop() && + !freezing(current)) { schedule(); continue; } @@ -4495,91 +4506,128 @@ static int setup_proc_entry( struct net_device *dev, apriv->proc_entry = create_proc_entry(apriv->proc_name, S_IFDIR|airo_perm, airo_entry); - apriv->proc_entry->uid = proc_uid; - apriv->proc_entry->gid = proc_gid; - apriv->proc_entry->owner = THIS_MODULE; + if (!apriv->proc_entry) + goto fail; + apriv->proc_entry->uid = proc_uid; + apriv->proc_entry->gid = proc_gid; + apriv->proc_entry->owner = THIS_MODULE; /* Setup the StatsDelta */ entry = create_proc_entry("StatsDelta", S_IFREG | (S_IRUGO&proc_perm), apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_stats_delta; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_statsdelta_ops); /* Setup the Stats */ entry = create_proc_entry("Stats", S_IFREG | (S_IRUGO&proc_perm), apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_stats; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_stats_ops); /* Setup the Status */ entry = create_proc_entry("Status", S_IFREG | (S_IRUGO&proc_perm), apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_status; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_status_ops); /* Setup the Config */ entry = create_proc_entry("Config", S_IFREG | proc_perm, apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_config; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_config_ops); /* Setup the SSID */ entry = create_proc_entry("SSID", S_IFREG | proc_perm, apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_ssid; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_SSID_ops); /* Setup the APList */ entry = create_proc_entry("APList", S_IFREG | proc_perm, apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_aplist; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_APList_ops); /* Setup the BSSList */ entry = create_proc_entry("BSSList", S_IFREG | proc_perm, apriv->proc_entry); + if (!entry) + goto fail_bsslist; entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_BSSList_ops); /* Setup the WepKey */ entry = create_proc_entry("WepKey", S_IFREG | proc_perm, apriv->proc_entry); - entry->uid = proc_uid; - entry->gid = proc_gid; + if (!entry) + goto fail_wepkey; + entry->uid = proc_uid; + entry->gid = proc_gid; entry->data = dev; - entry->owner = THIS_MODULE; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_wepkey_ops); return 0; + +fail_wepkey: + remove_proc_entry("BSSList", apriv->proc_entry); +fail_bsslist: + remove_proc_entry("APList", apriv->proc_entry); +fail_aplist: + remove_proc_entry("SSID", apriv->proc_entry); +fail_ssid: + remove_proc_entry("Config", apriv->proc_entry); +fail_config: + remove_proc_entry("Status", apriv->proc_entry); +fail_status: + remove_proc_entry("Stats", apriv->proc_entry); +fail_stats: + remove_proc_entry("StatsDelta", apriv->proc_entry); +fail_stats_delta: + remove_proc_entry(apriv->proc_name, airo_entry); +fail: + return -ENOMEM; } static int takedown_proc_entry( struct net_device *dev, @@ -5924,7 +5972,6 @@ static int airo_get_essid(struct net_device *dev, /* Get the current SSID */ memcpy(extra, status_rid.SSID, status_rid.SSIDlen); - extra[status_rid.SSIDlen] = '\0'; /* If none, we may want to get the one that was set */ /* Push it out ! */ diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 31eed85de60..0c07b8b7250 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1678,11 +1678,9 @@ static int atmel_get_essid(struct net_device *dev, /* Get the current SSID */ if (priv->new_SSID_size != 0) { memcpy(extra, priv->new_SSID, priv->new_SSID_size); - extra[priv->new_SSID_size] = '\0'; dwrq->length = priv->new_SSID_size; } else { memcpy(extra, priv->SSID, priv->SSID_size); - extra[priv->SSID_size] = '\0'; dwrq->length = priv->SSID_size; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 76e3aed4b47..978ed099e28 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -705,11 +705,30 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) struct bcm43xx_dmaring *ring; int err = -ENOMEM; int dma64 = 0; - u32 sbtmstatehi; + u64 mask = bcm43xx_get_supported_dma_mask(bcm); + int nobits; - sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); - if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT) + if (mask == DMA_64BIT_MASK) { dma64 = 1; + nobits = 64; + } else if (mask == DMA_32BIT_MASK) + nobits = 32; + else + nobits = 30; + err = pci_set_dma_mask(bcm->pci_dev, mask); + err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask); + if (err) { +#ifdef CONFIG_BCM43XX_PIO + printk(KERN_WARNING PFX "DMA not supported on this device." + " Falling back to PIO.\n"); + bcm->__using_pio = 1; + return -ENOSYS; +#else + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " + "Please recompile the driver with PIO support.\n"); + return -ENODEV; +#endif /* CONFIG_BCM43XX_PIO */ + } /* setup TX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64); @@ -755,8 +774,7 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) dma->rx_ring3 = ring; } - dprintk(KERN_INFO PFX "%s DMA initialized\n", - dma64 ? "64-bit" : "32-bit"); + dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits); err = 0; out: return err; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index e04bcaddd1d..d1105e569a4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -4,6 +4,7 @@ #include <linux/list.h> #include <linux/spinlock.h> #include <linux/workqueue.h> +#include <linux/dma-mapping.h> #include <linux/linkage.h> #include <asm/atomic.h> @@ -314,6 +315,23 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb); void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); +/* Helper function that returns the dma mask for this device. */ +static inline +u64 bcm43xx_get_supported_dma_mask(struct bcm43xx_private *bcm) +{ + int dma64 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH) & + BCM43xx_SBTMSTATEHIGH_DMA64BIT; + u16 mmio_base = bcm43xx_dmacontroller_base(dma64, 0); + u32 mask = BCM43xx_DMA32_TXADDREXT_MASK; + + if (dma64) + return DMA_64BIT_MASK; + bcm43xx_write32(bcm, mmio_base + BCM43xx_DMA32_TXCTL, mask); + if (bcm43xx_read32(bcm, mmio_base + BCM43xx_DMA32_TXCTL) & mask) + return DMA_32BIT_MASK; + return DMA_30BIT_MASK; +} + #else /* CONFIG_BCM43XX_DMA */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index c3f90c8563d..7d383a27b92 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -189,20 +189,24 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) case BCM43xx_LED_INACTIVE: continue; case BCM43xx_LED_OFF: + case BCM43xx_LED_BCM4303_3: break; case BCM43xx_LED_ON: turn_on = 1; break; case BCM43xx_LED_ACTIVITY: + case BCM43xx_LED_BCM4303_0: turn_on = activity; break; case BCM43xx_LED_RADIO_ALL: turn_on = radio->enabled; break; case BCM43xx_LED_RADIO_A: + case BCM43xx_LED_BCM4303_2: turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); break; case BCM43xx_LED_RADIO_B: + case BCM43xx_LED_BCM4303_1: turn_on = (radio->enabled && (phy->type == BCM43xx_PHYTYPE_B || phy->type == BCM43xx_PHYTYPE_G)); @@ -242,7 +246,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) //TODO break; case BCM43xx_LED_ASSOC: - if (bcm->softmac->associated) + if (bcm->softmac->associnfo.associated) turn_on = 1; break; #ifdef CONFIG_BCM43XX_DEBUG @@ -257,7 +261,8 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) continue; #endif /* CONFIG_BCM43XX_DEBUG */ default: - assert(0); + dprintkl(KERN_INFO PFX "Bad value in leds_update," + " led->behaviour: 0x%x\n", led->behaviour); }; if (led->activelow) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h index d3716cf3aeb..811e14a8119 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -46,6 +46,12 @@ enum { /* LED behaviour values */ BCM43xx_LED_TEST_BLINKSLOW, BCM43xx_LED_TEST_BLINKMEDIUM, BCM43xx_LED_TEST_BLINKFAST, + + /* Misc values for BCM4303 */ + BCM43xx_LED_BCM4303_0 = 0x2B, + BCM43xx_LED_BCM4303_1 = 0x78, + BCM43xx_LED_BCM4303_2 = 0x2E, + BCM43xx_LED_BCM4303_3 = 0x19, }; int bcm43xx_leds_init(struct bcm43xx_private *bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index bad3452ea89..a1b783813d8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -746,7 +746,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) if (err) goto err_ctlreg; spromctl |= 0x10; /* SPROM WRITE enable. */ - bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); if (err) goto err_ctlreg; /* We must burn lots of CPU cycles here, but that does not @@ -768,7 +768,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) mdelay(20); } spromctl &= ~0x10; /* SPROM WRITE enable. */ - bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); if (err) goto err_ctlreg; mdelay(500); @@ -1463,6 +1463,23 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm) } } +static void drain_txstatus_queue(struct bcm43xx_private *bcm) +{ + u32 dummy; + + if (bcm->current_core->rev < 5) + return; + /* Read all entries from the microcode TXstatus FIFO + * and throw them away. + */ + while (1) { + dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); + if (!dummy) + break; + dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); + } +} + static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) { bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); @@ -2925,10 +2942,13 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, bcm43xx_write16(bcm, 0x043C, 0x000C); if (active_wlcore) { - if (bcm43xx_using_pio(bcm)) + if (bcm43xx_using_pio(bcm)) { err = bcm43xx_pio_init(bcm); - else + } else { err = bcm43xx_dma_init(bcm); + if (err == -ENOSYS) + err = bcm43xx_pio_init(bcm); + } if (err) goto err_chip_cleanup; } @@ -3160,17 +3180,30 @@ static int estimate_periodic_work_badness(unsigned int state) static void bcm43xx_periodic_work_handler(void *d) { struct bcm43xx_private *bcm = d; + struct net_device *net_dev = bcm->net_dev; unsigned long flags; u32 savedirqs = 0; int badness; + unsigned long orig_trans_start = 0; + mutex_lock(&bcm->mutex); badness = estimate_periodic_work_badness(bcm->periodic_state); if (badness > BADNESS_LIMIT) { /* Periodic work will take a long time, so we want it to * be preemtible. */ - mutex_lock(&bcm->mutex); - netif_tx_disable(bcm->net_dev); + + netif_tx_lock_bh(net_dev); + /* We must fake a started transmission here, as we are going to + * disable TX. If we wouldn't fake a TX, it would be possible to + * trigger the netdev watchdog, if the last real TX is already + * some time on the past (slightly less than 5secs) + */ + orig_trans_start = net_dev->trans_start; + net_dev->trans_start = jiffies; + netif_stop_queue(net_dev); + netif_tx_unlock_bh(net_dev); + spin_lock_irqsave(&bcm->irq_lock, flags); bcm43xx_mac_suspend(bcm); if (bcm43xx_using_pio(bcm)) @@ -3182,7 +3215,6 @@ static void bcm43xx_periodic_work_handler(void *d) /* Periodic work should take short time, so we want low * locking overhead. */ - mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); } @@ -3196,6 +3228,7 @@ static void bcm43xx_periodic_work_handler(void *d) bcm43xx_pio_thaw_txqueues(bcm); bcm43xx_mac_enable(bcm); netif_wake_queue(bcm->net_dev); + net_dev->trans_start = orig_trans_start; } mmiowb(); spin_unlock_irqrestore(&bcm->irq_lock, flags); @@ -3516,6 +3549,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); bcm43xx_security_init(bcm); + drain_txstatus_queue(bcm); ieee80211softmac_start(bcm->net_dev); /* Let's go! Be careful after enabling the IRQs. @@ -3993,8 +4027,6 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, struct net_device *net_dev, struct pci_dev *pci_dev) { - int err; - bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); @@ -4012,22 +4044,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, (void (*)(unsigned long))bcm43xx_interrupt_tasklet, (unsigned long)bcm); tasklet_disable_nosync(&bcm->isr_tasklet); - if (modparam_pio) { + if (modparam_pio) bcm->__using_pio = 1; - } else { - err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK); - err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK); - if (err) { -#ifdef CONFIG_BCM43XX_PIO - printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); - bcm->__using_pio = 1; -#else - printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " - "Recompile the driver with PIO support, please.\n"); - return -ENODEV; -#endif /* CONFIG_BCM43XX_PIO */ - } - } bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; /* default to sw encryption for now */ @@ -4208,7 +4226,11 @@ static int bcm43xx_resume(struct pci_dev *pdev) dprintk(KERN_INFO PFX "Resuming...\n"); pci_set_power_state(pdev, 0); - pci_enable_device(pdev); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Failure with pci_enable_device!\n"); + return err; + } pci_restore_state(pdev); bcm43xx_chipset_attach(bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 9b7b15cf656..d27016f8c73 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -847,7 +847,7 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d unsigned long flags; wstats = &bcm->stats.wstats; - if (!mac->associated) { + if (!mac->associnfo.associated) { wstats->miss.beacon = 0; // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here? wstats->discard.retries = 0; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 686d895116d..f63909e4bc3 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -887,6 +887,13 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_PROD_ID123( "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", 0xc7b8df9d, 0x1700d087, 0x4b74baa0), + PCMCIA_DEVICE_PROD_ID123( + "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", + "Ver. 1.00", + 0x5cd01705, 0x4271660f, 0x9d08ee12), + PCMCIA_DEVICE_PROD_ID123( + "corega", "WL PCCL-11", "ISL37300P", + 0xa21501a, 0x59868926, 0xc9049a39), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 6dfa041be66..bc81b13a5a2 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -364,7 +364,7 @@ static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, pos = 0; while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { - if (pos + cis[pos + 1] >= CIS_MAX_LEN) + if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN) goto cis_error; switch (cis[pos]) { @@ -391,7 +391,7 @@ static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, break; case CISTPL_MANFID: - if (cis[pos + 1] < 5) + if (cis[pos + 1] < 4) goto cis_error; manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index b779c7dcc1a..336cabac13b 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2457,6 +2457,7 @@ void free_orinocodev(struct net_device *dev) /* Wireless extensions */ /********************************************************************/ +/* Return : < 0 -> error code ; >= 0 -> length */ static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]) { @@ -2501,9 +2502,9 @@ static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, len = le16_to_cpu(essidbuf.len); BUG_ON(len > IW_ESSID_MAX_SIZE); - memset(buf, 0, IW_ESSID_MAX_SIZE+1); + memset(buf, 0, IW_ESSID_MAX_SIZE); memcpy(buf, p, len); - buf[len] = '\0'; + err = len; fail_unlock: orinoco_unlock(priv, &flags); @@ -3027,17 +3028,18 @@ static int orinoco_ioctl_getessid(struct net_device *dev, if (netif_running(dev)) { err = orinoco_hw_get_essid(priv, &active, essidbuf); - if (err) + if (err < 0) return err; + erq->length = err; } else { if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1); + memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); + erq->length = strlen(priv->desired_essid); orinoco_unlock(priv, &flags); } erq->flags = 1; - erq->length = strlen(essidbuf); return 0; } @@ -3075,10 +3077,10 @@ static int orinoco_ioctl_getnick(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE); orinoco_unlock(priv, &flags); - nrq->length = strlen(nickbuf); + nrq->length = strlen(priv->nick); return 0; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 0b381d77015..7fbfc9e41d0 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1198,7 +1198,6 @@ static int ray_get_essid(struct net_device *dev, /* Get the essid that was set */ memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - extra[IW_ESSID_MAX_SIZE] = '\0'; /* Push it out ! */ dwrq->length = strlen(extra); diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 30057a335a7..36b29ff0581 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -193,10 +193,8 @@ static void zd1201_usbrx(struct urb *urb) struct sk_buff *skb; unsigned char type; - if (!zd) { - free = 1; - goto exit; - } + if (!zd) + return; switch(urb->status) { case -EILSEQ: diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 2d12837052b..a7d29bddb29 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1099,7 +1099,7 @@ static void link_led_handler(void *p) int r; spin_lock_irq(&mac->lock); - is_associated = sm->associated != 0; + is_associated = sm->associnfo.associated != 0; spin_unlock_irq(&mac->lock); r = zd_chip_control_leds(chip, diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c index e3e19277030..ec44efdbb84 100644 --- a/drivers/parport/parport_ip32.c +++ b/drivers/parport/parport_ip32.c @@ -780,7 +780,7 @@ static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id) enum parport_ip32_irq_mode irq_mode = priv->irq_mode; switch (irq_mode) { case PARPORT_IP32_IRQ_FWD: - parport_generic_irq(irq, p, regs); + parport_generic_irq(irq, p); break; case PARPORT_IP32_IRQ_HERE: parport_ip32_wakeup(p); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 30294127a0a..5f1b9f58070 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -19,7 +19,7 @@ config PCI_MSI config PCI_MULTITHREAD_PROBE bool "PCI Multi-threaded probe (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL && BROKEN help Say Y here if you want the PCI core to spawn a new thread for every PCI device that is probed. This can cause a huge @@ -55,7 +55,7 @@ config PCI_DEBUG config HT_IRQ bool "Interrupts on hypertransport devices" default y - depends on X86_LOCAL_APIC && X86_IO_APIC + depends on PCI && X86_LOCAL_APIC && X86_IO_APIC help This allows native hypertransport devices to use interrupts. diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 51cb9f817c2..270a33cc08f 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -29,10 +29,10 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h> #include <acpi/actypes.h> -#include "pci_hotplug.h" #define MY_NAME "acpi_pcihp" diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7fff07e877c..59c5b242d86 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -38,7 +38,7 @@ #include <linux/acpi.h> #include <linux/kobject.h> /* for KOBJ_NAME_LEN */ #include <linux/mutex.h> -#include "pci_hotplug.h" +#include <linux/pci_hotplug.h> #define dbg(format, arg...) \ do { \ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index e2fef60c2d0..c57d9d5ce84 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -37,10 +37,10 @@ #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/slab.h> #include <linux/smp.h> #include <linux/smp_lock.h> -#include "pci_hotplug.h" #include "acpiphp.h" #define MY_NAME "acpiphp" diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 83e8e4412de..16167b01626 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -45,11 +45,11 @@ #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/smp_lock.h> #include <linux/mutex.h> #include "../pci.h" -#include "pci_hotplug.h" #include "acpiphp.h" static LIST_HEAD(bridge_list); @@ -1807,8 +1807,8 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) /* - * latch closed: 1 - * latch open: 0 + * latch open: 1 + * latch closed: 0 */ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) { @@ -1816,7 +1816,7 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) sta = get_slot_status(slot); - return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; + return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1; } diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index d0a07d9ab30..bd40aee10e1 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -35,7 +35,6 @@ #include <linux/moduleparam.h> #include "acpiphp.h" -#include "pci_hotplug.h" #define DRIVER_VERSION "1.0.1" #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d06ab404513..684551559d4 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -29,12 +29,12 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <asm/atomic.h> #include <linux/delay.h> -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 4afcaffd031..7b1beaad275 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -26,9 +26,9 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/proc_fs.h> #include "../pci.h" -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define MY_NAME "cpci_hotplug" diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c index e847f0d6c7f..f3852a6b74e 100644 --- a/drivers/pci/hotplug/cpcihp_generic.c +++ b/drivers/pci/hotplug/cpcihp_generic.c @@ -84,7 +84,7 @@ static int __init validate_parameters(void) if(!bridge) { info("not configured, disabling."); - return 1; + return -EINVAL; } str = bridge; if(!*str) @@ -147,7 +147,7 @@ static int __init cpcihp_generic_init(void) info(DRIVER_DESC " version: " DRIVER_VERSION); status = validate_parameters(); - if(status != 0) + if (status) return status; r = request_region(port, 1, "#ENUM hotswap signal register"); diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index ea040c32f47..298ad7f3f4f 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -28,7 +28,6 @@ #ifndef _CPQPHP_H #define _CPQPHP_H -#include "pci_hotplug.h" #include <linux/interrupt.h> #include <asm/io.h> /* for read? and write? functions */ #include <linux/delay.h> /* for delays */ diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 1fc259913b6..5617cfdadc5 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -37,6 +37,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 3ec2ad7db49..79ff6b4de3a 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -36,6 +36,7 @@ #include <linux/wait.h> #include <linux/smp_lock.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include "cpqphp.h" static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index cf087891753..298a6cfd840 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> #include <asm/uaccess.h> #include "cpqphp.h" diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 0d9688952f4..fc7c74d7259 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -33,6 +33,7 @@ #include <linux/workqueue.h> #include <linux/proc_fs.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 5bab666cd67..634f74d919d 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -32,6 +32,7 @@ #include <linux/proc_fs.h> #include <linux/workqueue.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/debugfs.h> #include "cpqphp.h" diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 05a4f0f9018..e27907c91d9 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -35,10 +35,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> -#include "pci_hotplug.h" #include "../pci.h" #if !defined(MODULE) @@ -181,7 +181,9 @@ static void pci_rescan_slot(struct pci_dev *temp) if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { temp->hdr_type = hdr_type & 0x7f; - if (!pci_find_slot(bus->number, temp->devfn)) { + if ((dev = pci_get_slot(bus, temp->devfn)) != NULL) + pci_dev_put(dev); + else { dev = pci_scan_single_device(bus, temp->devfn); if (dev) { dbg("New device on %s function %x:%x\n", @@ -205,7 +207,9 @@ static void pci_rescan_slot(struct pci_dev *temp) continue; temp->hdr_type = hdr_type & 0x7f; - if (!pci_find_slot(bus->number, temp->devfn)) { + if ((dev = pci_get_slot(bus, temp->devfn)) != NULL) + pci_dev_put(dev); + else { dev = pci_scan_single_device(bus, temp->devfn); if (dev) { dbg("New device on %s function %x:%x\n", @@ -305,7 +309,7 @@ static int disable_slot(struct hotplug_slot *slot) /* search for subfunctions and disable them first */ if (!(dslot->dev->devfn & 7)) { for (func = 1; func < 8; func++) { - dev = pci_find_slot(dslot->dev->bus->number, + dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); if (dev) { hslot = get_slot_from_dev(dev); @@ -315,6 +319,7 @@ static int disable_slot(struct hotplug_slot *slot) err("Hotplug slot not found for subfunction of PCI device\n"); return -ENODEV; } + pci_dev_put(dev); } else dbg("No device in slot found\n"); } diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index dba6d8ca9bd..612d9630150 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -30,7 +30,7 @@ * */ -#include "pci_hotplug.h" +#include <linux/pci_hotplug.h> extern int ibmphp_debug; diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h deleted file mode 100644 index 772523dc386..00000000000 --- a/drivers/pci/hotplug/pci_hotplug.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * PCI HotPlug Core Functions - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com> - * - */ -#ifndef _PCI_HOTPLUG_H -#define _PCI_HOTPLUG_H - - -/* These values come from the PCI Hotplug Spec */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_ECC = 0x05, - PCI_SPEED_100MHz_PCIX_ECC = 0x06, - PCI_SPEED_133MHz_PCIX_ECC = 0x07, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0x12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCI_SPEED_UNKNOWN = 0xff, -}; - -/* These values come from the PCI Express Spec */ -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0x00, - PCIE_LNK_X1 = 0x01, - PCIE_LNK_X2 = 0x02, - PCIE_LNK_X4 = 0x04, - PCIE_LNK_X8 = 0x08, - PCIE_LNK_X12 = 0x0C, - PCIE_LNK_X16 = 0x10, - PCIE_LNK_X32 = 0x20, - PCIE_LNK_WIDTH_UNKNOWN = 0xFF, -}; - -enum pcie_link_speed { - PCIE_2PT5GB = 0x14, - PCIE_LNK_SPEED_UNKNOWN = 0xFF, -}; - -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); - -/** - * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @enable_slot: Called when the user wants to enable a specific pci slot - * @disable_slot: Called when the user wants to disable a specific pci slot - * @set_attention_status: Called to set the specific slot's attention LED to - * the specified value - * @hardware_test: Called to run a specified hardware test on the specified - * slot. - * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_address: Called to get pci address of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_max_bus_speed: Called to get the max bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_cur_bus_speed: Called to get the current bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * - * The table of function pointers that is passed to the hotplug pci core by a - * hotplug pci driver. These functions are called by the hotplug pci core when - * the user wants to do something to a specific slot (query it for information, - * set an LED, enable / disable power, etc.) - */ -struct hotplug_slot_ops { - struct module *owner; - int (*enable_slot) (struct hotplug_slot *slot); - int (*disable_slot) (struct hotplug_slot *slot); - int (*set_attention_status) (struct hotplug_slot *slot, u8 value); - int (*hardware_test) (struct hotplug_slot *slot, u32 value); - int (*get_power_status) (struct hotplug_slot *slot, u8 *value); - int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); - int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); - int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); - int (*get_address) (struct hotplug_slot *slot, u32 *value); - int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); - int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); -}; - -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_present: if there is a pci board present in the slot or not (1/0) - * @address: (domain << 16 | bus << 8 | dev) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; - u32 address; - enum pci_bus_speed max_bus_speed; - enum pci_bus_speed cur_bus_speed; -}; - -/** - * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. - * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the initial values for - * this slot. - * @release: called during pci_hp_deregister to free memory allocated in a - * hotplug_slot structure. - * @private: used by the hotplug pci controller driver to store whatever it - * needs. - */ -struct hotplug_slot { - char *name; - struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; - void (*release) (struct hotplug_slot *slot); - void *private; - - /* Variables below this are for use only by the hotplug pci core. */ - struct list_head slot_list; - struct kobject kobj; -}; -#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) - -extern int pci_hp_register (struct hotplug_slot *slot); -extern int pci_hp_deregister (struct hotplug_slot *slot); -extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, - struct hotplug_slot_info *info); -extern struct subsystem pci_hotplug_slots_subsys; - -/* PCI Setting Record (Type 0) */ -struct hpp_type0 { - u32 revision; - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -/* PCI-X Setting Record (Type 1) */ -struct hpp_type1 { - u32 revision; - u8 max_mem_read; - u8 avg_max_split; - u16 tot_max_split; -}; - -/* PCI Express Setting Record (Type 2) */ -struct hpp_type2 { - u32 revision; - u32 unc_err_mask_and; - u32 unc_err_mask_or; - u32 unc_err_sever_and; - u32 unc_err_sever_or; - u32 cor_err_mask_and; - u32 cor_err_mask_or; - u32 adv_err_cap_and; - u32 adv_err_cap_or; - u16 pci_exp_devctl_and; - u16 pci_exp_devctl_or; - u16 pci_exp_lnkctl_and; - u16 pci_exp_lnkctl_or; - u32 sec_unc_err_sever_and; - u32 sec_unc_err_sever_or; - u32 sec_unc_err_mask_and; - u32 sec_unc_err_mask_or; -}; - -struct hotplug_params { - struct hpp_type0 *t0; /* Type0: NULL if not available */ - struct hpp_type1 *t1; /* Type1: NULL if not available */ - struct hpp_type2 *t2; /* Type2: NULL if not available */ - struct hpp_type0 type0_data; - struct hpp_type1 type1_data; - struct hpp_type2 type2_data; -}; - -#ifdef CONFIG_ACPI -#include <acpi/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/actypes.h> -extern acpi_status acpi_run_oshp(acpi_handle handle); -extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, - struct hotplug_params *hpp); -int acpi_root_bridge(acpi_handle handle); -#endif -#endif - diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index e2823ea9c4e..f5d632e7232 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -21,9 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to <greg@kroah.com> - * - * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * Send feedback to <kristen.c.accardi@intel.com> * */ @@ -32,6 +30,8 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/list.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> #include <linux/pagemap.h> #include <linux/slab.h> #include <linux/smp_lock.h> @@ -39,11 +39,8 @@ #include <linux/mount.h> #include <linux/namei.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <asm/uaccess.h> -#include <linux/kobject.h> -#include <linux/sysfs.h> -#include "pci_hotplug.h" - #define MY_NAME "pci_hotplug" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index eaea9d36a1b..4fb12fcda56 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -31,11 +31,11 @@ #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/delay.h> #include <linux/sched.h> /* signal_pending() */ #include <linux/pcieport_if.h> #include <linux/mutex.h> -#include "pci_hotplug.h" #define MY_NAME "pciehp" @@ -92,6 +92,7 @@ struct php_ctlr_state_s { struct controller { struct controller *next; struct mutex crit_sect; /* critical section mutex */ + struct mutex ctrl_lock; /* controller lock */ struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ @@ -166,10 +167,10 @@ struct controller { * error Messages */ #define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_button_on "PCI slot #%d - powering on due to button press.\n" -#define msg_button_off "PCI slot #%d - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" +#define msg_button_on "PCI slot #%s - powering on due to button press.\n" +#define msg_button_off "PCI slot #%s - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n" /* controller functions */ extern int pciehp_event_start_thread (void); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index c67b7c3f1dd..f93e81e2d2c 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ } /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ @@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) { /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); goto err_out_free_ctrl_slot; } else /* Wait for the command to complete */ @@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return 0; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 41290a106bd..372c63e35aa 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -43,6 +43,11 @@ static int event_finished; static unsigned long pushbutton_pending; /* = 0 */ static unsigned long surprise_rm_pending; /* = 0 */ +static inline char *slot_name(struct slot *p_slot) +{ + return p_slot->hotplug_slot->name; +} + u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) { struct controller *ctrl = (struct controller *) inst_id; @@ -68,7 +73,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button pressed on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_BUTTON_PRESS; if ((p_slot->state == BLINKINGON_STATE) @@ -78,7 +83,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) * or hot-remove */ taskInfo->event_type = INT_BUTTON_CANCEL; - info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button cancel on Slot(%s)\n", slot_name(p_slot)); } else if ((p_slot->state == POWERON_STATE) || (p_slot->state == POWEROFF_STATE)) { /* Ignore if the slot is on power-on or power-off state; this @@ -86,7 +91,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) * hot-remove is undergoing */ taskInfo->event_type = INT_BUTTON_IGNORE; - info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button ignore on Slot(%s)\n", slot_name(p_slot)); } if (rc) @@ -122,13 +127,13 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) /* * Switch opened */ - info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Latch open on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_SWITCH_OPEN; } else { /* * Switch closed */ - info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Latch close on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_SWITCH_CLOSE; } @@ -166,13 +171,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) /* * Card Present */ - info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Card present on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Card not present on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_PRESENCE_OFF; } @@ -206,13 +211,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) /* * power fault Cleared */ - info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { /* * power fault */ - info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Power fault on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_POWER_FAULT; info("power fault bit %x set\n", hp_slot); } @@ -229,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return; } wait_for_ctrl_irq (ctrl); @@ -249,14 +254,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) if (ATTN_LED(ctrl->ctrlcap)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return; } wait_for_ctrl_irq (ctrl); } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); } /** @@ -279,13 +284,13 @@ static int board_added(struct slot *p_slot) ctrl->slot_device_offset, hp_slot); /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (POWER_CTRL(ctrl->ctrlcap)) { /* Power on slot */ rc = p_slot->hpc_ops->power_on_slot(p_slot); if (rc) { - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return -1; } @@ -301,7 +306,7 @@ static int board_added(struct slot *p_slot) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); /* Wait for ~1 second */ wait_for_ctrl_irq (ctrl); @@ -335,7 +340,7 @@ static int board_added(struct slot *p_slot) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); if (PWR_LED(ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); p_slot->hpc_ops->green_led_on(p_slot); @@ -343,7 +348,7 @@ static int board_added(struct slot *p_slot) wait_for_ctrl_irq (ctrl); /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); } return 0; @@ -375,14 +380,14 @@ static int remove_board(struct slot *p_slot) dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (POWER_CTRL(ctrl->ctrlcap)) { /* power off slot */ rc = p_slot->hpc_ops->power_off_slot(p_slot); if (rc) { err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return rc; } /* Wait for the command to complete */ @@ -398,7 +403,7 @@ static int remove_board(struct slot *p_slot) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return 0; } @@ -445,7 +450,7 @@ static void pciehp_pushbutton_thread(unsigned long slot) if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->crit_sect); + mutex_lock(&p_slot->ctrl->ctrl_lock); p_slot->hpc_ops->green_led_off(p_slot); @@ -453,7 +458,7 @@ static void pciehp_pushbutton_thread(unsigned long slot) wait_for_ctrl_irq (p_slot->ctrl); /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->crit_sect); + mutex_unlock(&p_slot->ctrl->ctrl_lock); } p_slot->state = STATIC_STATE; } @@ -495,7 +500,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot) if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->crit_sect); + mutex_lock(&p_slot->ctrl->ctrl_lock); p_slot->hpc_ops->green_led_off(p_slot); @@ -503,7 +508,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot) wait_for_ctrl_irq (p_slot->ctrl); /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->crit_sect); + mutex_unlock(&p_slot->ctrl->ctrl_lock); } p_slot->state = STATIC_STATE; } @@ -616,7 +621,7 @@ static void interrupt_event_handler(struct controller *ctrl) switch (p_slot->state) { case BLINKINGOFF_STATE: /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (PWR_LED(ctrl->ctrlcap)) { p_slot->hpc_ops->green_led_on(p_slot); @@ -630,11 +635,11 @@ static void interrupt_event_handler(struct controller *ctrl) wait_for_ctrl_irq (ctrl); } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); break; case BLINKINGON_STATE: /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (PWR_LED(ctrl->ctrlcap)) { p_slot->hpc_ops->green_led_off(p_slot); @@ -647,14 +652,14 @@ static void interrupt_event_handler(struct controller *ctrl) wait_for_ctrl_irq (ctrl); } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); break; default: warn("Not a valid state\n"); return; } - info(msg_button_cancel, p_slot->number); + info(msg_button_cancel, slot_name(p_slot)); p_slot->state = STATIC_STATE; } /* ***********Button Pressed (No action on 1st press...) */ @@ -667,16 +672,16 @@ static void interrupt_event_handler(struct controller *ctrl) /* slot is on */ dbg("slot is on\n"); p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); + info(msg_button_off, slot_name(p_slot)); } else { /* slot is off */ dbg("slot is off\n"); p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); + info(msg_button_on, slot_name(p_slot)); } /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); /* blink green LED and turn off amber */ if (PWR_LED(ctrl->ctrlcap)) { @@ -693,7 +698,7 @@ static void interrupt_event_handler(struct controller *ctrl) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); init_timer(&p_slot->task_event); p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ @@ -708,7 +713,7 @@ static void interrupt_event_handler(struct controller *ctrl) if (POWER_CTRL(ctrl->ctrlcap)) { dbg("power fault\n"); /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (ATTN_LED(ctrl->ctrlcap)) { p_slot->hpc_ops->set_attention_status(p_slot, 1); @@ -721,7 +726,7 @@ static void interrupt_event_handler(struct controller *ctrl) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); } } /***********SURPRISE REMOVAL********************/ @@ -760,14 +765,16 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: no adapter on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } if (MRL_SENS(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: latch open on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -776,12 +783,12 @@ int pciehp_enable_slot(struct slot *p_slot) if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: already enabled on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } } - mutex_unlock(&p_slot->ctrl->crit_sect); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); @@ -790,9 +797,9 @@ int pciehp_enable_slot(struct slot *p_slot) p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); } - if (p_slot) - update_slot_info(p_slot); + update_slot_info(p_slot); + mutex_unlock(&p_slot->ctrl->crit_sect); return rc; } @@ -811,7 +818,8 @@ int pciehp_disable_slot(struct slot *p_slot) if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: no adapter on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -820,7 +828,8 @@ int pciehp_disable_slot(struct slot *p_slot) if (MRL_SENS(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: latch open on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -829,16 +838,17 @@ int pciehp_disable_slot(struct slot *p_slot) if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { - info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: already disabled slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } } - mutex_unlock(&p_slot->ctrl->crit_sect); - ret = remove_board(p_slot); update_slot_info(p_slot); + + mutex_unlock(&p_slot->ctrl->crit_sect); return ret; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 703a64a39fe..1c551c697c3 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); + mutex_init(&ctrl->ctrl_lock); + /* setup wait queue */ init_waitqueue_head(&ctrl->queue); diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 2b9e10e3861..50bcd3fe61d 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -33,8 +33,8 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> -#include "pci_hotplug.h" #define SLOT_NAME_SIZE 10 struct slot { diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index db69be85b45..6c5be3ff578 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -14,7 +14,7 @@ */ #include <linux/kobject.h> #include <linux/string.h> -#include "pci_hotplug.h" +#include <linux/pci_hotplug.h> #include "rpadlpar.h" #define DLPAR_KOBJ_NAME "control" diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 310b6186c0e..2e7accf0f73 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -28,7 +28,7 @@ #define _PPC64PHP_H #include <linux/pci.h> -#include "pci_hotplug.h" +#include <linux/pci_hotplug.h> #define DR_INDICATOR 9002 #define DR_ENTITY_SENSE 9003 diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 7288a3eccfb..141486df235 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/slab.h> #include <linux/smp.h> #include <linux/smp_lock.h> @@ -36,7 +37,6 @@ #include "../pci.h" /* for pci_add_new_bus */ /* and pci_do_scan_bus */ #include "rpaphp.h" -#include "pci_hotplug.h" int debug; static struct semaphore rpaphp_sem; diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f31d83c2c63..b62ad31a973 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/proc_fs.h> #include <linux/types.h> #include <linux/mutex.h> @@ -29,7 +30,6 @@ #include <asm/sn/types.h> #include "../pci.h" -#include "pci_hotplug.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index c7103ac5cd0..ea2087c3414 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -31,12 +31,11 @@ #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/delay.h> #include <linux/sched.h> /* signal_pending(), struct timer_list */ #include <linux/mutex.h> -#include "pci_hotplug.h" - #if !defined(MODULE) #define MY_NAME "shpchp" #else @@ -103,7 +102,6 @@ struct controller { u32 cap_offset; unsigned long mmio_base; unsigned long mmio_size; - volatile int cmd_busy; }; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 4d8aee11913..83a5226ba9e 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -302,21 +302,51 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) add_timer(&php_ctlr->int_poll_timer); } +static inline int is_ctrl_busy(struct controller *ctrl) +{ + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS); + return cmd_status & 0x1; +} + +/* + * Returns 1 if SHPC finishes executing a command within 1 sec, + * otherwise returns 0. + */ +static inline int shpc_poll_ctrl_busy(struct controller *ctrl) +{ + int i; + + if (!is_ctrl_busy(ctrl)) + return 1; + + /* Check every 0.1 sec for a total of 1 sec */ + for (i = 0; i < 10; i++) { + msleep(100); + if (!is_ctrl_busy(ctrl)) + return 1; + } + + return 0; +} + static inline int shpc_wait_cmd(struct controller *ctrl) { int retval = 0; - unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000; - unsigned long timeout = msecs_to_jiffies(timeout_msec); - int rc = wait_event_interruptible_timeout(ctrl->queue, - !ctrl->cmd_busy, timeout); - if (!rc) { + unsigned long timeout = msecs_to_jiffies(1000); + int rc; + + if (shpchp_poll_mode) + rc = shpc_poll_ctrl_busy(ctrl); + else + rc = wait_event_interruptible_timeout(ctrl->queue, + !is_ctrl_busy(ctrl), timeout); + if (!rc && is_ctrl_busy(ctrl)) { retval = -EIO; - err("Command not completed in %d msec\n", timeout_msec); + err("Command not completed in 1000 msec\n"); } else if (rc < 0) { retval = -EINTR; info("Command was interrupted by a signal\n"); } - ctrl->cmd_busy = 0; return retval; } @@ -327,26 +357,15 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) u16 cmd_status; int retval = 0; u16 temp_word; - int i; DBG_ENTER_ROUTINE mutex_lock(&slot->ctrl->cmd_lock); - for (i = 0; i < 10; i++) { - cmd_status = shpc_readw(ctrl, CMD_STATUS); - - if (!(cmd_status & 0x1)) - break; - /* Check every 0.1 sec for a total of 1 sec*/ - msleep(100); - } - - cmd_status = shpc_readw(ctrl, CMD_STATUS); - - if (cmd_status & 0x1) { + if (!shpc_poll_ctrl_busy(ctrl)) { /* After 1 sec and and the controller is still busy */ - err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__); + err("%s : Controller is still busy after 1 sec.\n", + __FUNCTION__); retval = -EBUSY; goto out; } @@ -358,7 +377,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) /* To make sure the Controller Busy bit is 0 before we send out the * command. */ - slot->ctrl->cmd_busy = 1; shpc_writew(ctrl, CMD, temp_word); /* @@ -908,7 +926,6 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) serr_int &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); - ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } @@ -1101,7 +1118,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) { struct php_ctlr_state_s *php_ctlr, *p; void *instance_id = ctrl; - int rc, num_slots = 0; + int rc = -1, num_slots = 0; u8 hp_slot; u32 shpc_base_offset; u32 tempdword, slot_reg, slot_config; @@ -1167,11 +1184,15 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); - if (pci_enable_device(pdev)) + rc = pci_enable_device(pdev); + if (rc) { + err("%s: pci_enable_device failed\n", __FUNCTION__); goto abort_free_ctlr; + } if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { err("%s: cannot reserve MMIO region\n", __FUNCTION__); + rc = -1; goto abort_free_ctlr; } @@ -1180,6 +1201,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, ctrl->mmio_size, ctrl->mmio_base); release_mem_region(ctrl->mmio_base, ctrl->mmio_size); + rc = -1; goto abort_free_ctlr; } dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); @@ -1282,8 +1304,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) */ if (atomic_add_return(1, &shpchp_num_controllers) == 1) { shpchp_wq = create_singlethread_workqueue("shpchpd"); - if (!shpchp_wq) - return -ENOMEM; + if (!shpchp_wq) { + rc = -ENOMEM; + goto abort_free_ctlr; + } } /* @@ -1313,8 +1337,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) /* We end up here for the many possible ways to fail this API. */ abort_free_ctlr: + if (php_ctlr->creg) + iounmap(php_ctlr->creg); kfree(php_ctlr); abort: DBG_LEAVE_ROUTINE - return -1; + return rc; } diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 0e27f2404a8..0a8d1cce9fa 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -25,97 +25,72 @@ static DEFINE_SPINLOCK(ht_irq_lock); struct ht_irq_cfg { struct pci_dev *dev; + /* Update callback used to cope with buggy hardware */ + ht_irq_update_t *update; unsigned pos; unsigned idx; + struct ht_irq_msg msg; }; -void write_ht_irq_low(unsigned int irq, u32 data) -{ - struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); -} -void write_ht_irq_high(unsigned int irq, u32 data) +void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { struct ht_irq_cfg *cfg = get_irq_data(irq); unsigned long flags; spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); -} - -u32 read_ht_irq_low(unsigned int irq) -{ - struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - u32 data; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + if (cfg->msg.address_lo != msg->address_lo) { + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_lo); + } + if (cfg->msg.address_hi != msg->address_hi) { + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); + pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); + } + if (cfg->update) + cfg->update(cfg->dev, irq, msg); spin_unlock_irqrestore(&ht_irq_lock, flags); - return data; + cfg->msg = *msg; } -u32 read_ht_irq_high(unsigned int irq) +void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - u32 data; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - spin_unlock_irqrestore(&ht_irq_lock, flags); - return data; + *msg = cfg->msg; } void mask_ht_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - unsigned long flags; - u32 data; + struct ht_irq_msg msg; cfg = get_irq_data(irq); - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - data |= 1; - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); + msg = cfg->msg; + msg.address_lo |= 1; + write_ht_irq_msg(irq, &msg); } void unmask_ht_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - unsigned long flags; - u32 data; + struct ht_irq_msg msg; cfg = get_irq_data(irq); - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - data &= ~1; - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); + msg = cfg->msg; + msg.address_lo &= ~1; + write_ht_irq_msg(irq, &msg); } /** - * ht_create_irq - create an irq and attach it to a device. + * __ht_create_irq - create an irq and attach it to a device. * @dev: The hypertransport device to find the irq capability on. * @idx: Which of the possible irqs to attach to. - * - * ht_create_irq is needs to be called for all hypertransport devices - * that generate irqs. + * @update: Function to be called when changing the htirq message * * The irq number of the new irq or a negative error value is returned. */ -int ht_create_irq(struct pci_dev *dev, int idx) +int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) { struct ht_irq_cfg *cfg; unsigned long flags; @@ -150,8 +125,12 @@ int ht_create_irq(struct pci_dev *dev, int idx) return -ENOMEM; cfg->dev = dev; + cfg->update = update; cfg->pos = pos; cfg->idx = 0x10 + (idx * 2); + /* Initialize msg to a value that will never match the first write. */ + cfg->msg.address_lo = 0xffffffff; + cfg->msg.address_hi = 0xffffffff; irq = create_irq(); if (irq < 0) { @@ -169,6 +148,21 @@ int ht_create_irq(struct pci_dev *dev, int idx) } /** + * ht_create_irq - create an irq and attach it to a device. + * @dev: The hypertransport device to find the irq capability on. + * @idx: Which of the possible irqs to attach to. + * + * ht_create_irq needs to be called for all hypertransport devices + * that generate irqs. + * + * The irq number of the new irq or a negative error value is returned. + */ +int ht_create_irq(struct pci_dev *dev, int idx) +{ + return __ht_create_irq(dev, idx, NULL); +} + +/** * ht_destroy_irq - destroy an irq created with ht_create_irq * * This reverses ht_create_irq removing the specified irq from @@ -186,5 +180,6 @@ void ht_destroy_irq(unsigned int irq) kfree(cfg); } +EXPORT_SYMBOL(__ht_create_irq); EXPORT_SYMBOL(ht_create_irq); EXPORT_SYMBOL(ht_destroy_irq); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f9fdc54473c..9fc9a34ef24 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -627,22 +627,24 @@ static int msix_capability_init(struct pci_dev *dev, * pci_msi_supported - check whether MSI may be enabled on device * @dev: pointer to the pci_dev data structure of MSI device function * - * MSI must be globally enabled and supported by the device and its root - * bus. But, the root bus is not easy to find since some architectures - * have virtual busses on top of the PCI hierarchy (for instance the - * hypertransport bus), while the actual bus where MSI must be supported - * is below. So we test the MSI flag on all parent busses and assume - * that no quirk will ever set the NO_MSI flag on a non-root bus. + * Look at global flags, the device itself, and its parent busses + * to return 0 if MSI are supported for the device. **/ static int pci_msi_supported(struct pci_dev * dev) { struct pci_bus *bus; + /* MSI must be globally enabled and supported by the device */ if (!pci_msi_enable || !dev || dev->no_msi) return -EINVAL; - /* check MSI flags of all parent busses */ + /* Any bridge which does NOT route MSI transactions from it's + * secondary bus to it's primary bus must set NO_MSI flag on + * the secondary pci_bus. + * We expect only arch-specific PCI host bus controller driver + * or quirks for specific PCI bridges to be setting NO_MSI. + */ for (bus = dev->bus; bus; bus = bus->parent) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b1c0c707d96..194f1d21d3d 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -265,6 +265,13 @@ static int pci_device_remove(struct device * dev) } /* + * If the device is still on, set the power state as "unknown", + * since it might change by the next time we load the driver. + */ + if (pci_dev->current_state == PCI_D0) + pci_dev->current_state = PCI_UNKNOWN; + + /* * We would love to complain here if pci_dev->is_enabled is set, that * the driver should have called pci_disable_device(), but the * unfortunate fact is there are too many odd BIOS and bridge setups @@ -288,6 +295,12 @@ static int pci_device_suspend(struct device * dev, pm_message_t state) suspend_report_result(drv->suspend, i); } else { pci_save_state(pci_dev); + /* + * mark its power state as "unknown", since we don't know if + * e.g. the BIOS will change its device state when we suspend. + */ + if (pci_dev->current_state == PCI_D0) + pci_dev->current_state = PCI_UNKNOWN; } return i; } diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index a1d2e979b17..f952bfea48a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -642,6 +642,9 @@ err: */ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) { + if (!sysfs_initialized) + return; + if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 67fcd176bab..3656e0349dd 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -9,6 +9,8 @@ #ifndef _PORTDRV_H_ #define _PORTDRV_H_ +#include <linux/compiler.h> + #if !defined(PCI_CAP_ID_PME) #define PCI_CAP_ID_PME 1 #endif @@ -39,7 +41,7 @@ extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state); extern int pcie_port_device_resume(struct pci_dev *dev); #endif extern void pcie_port_device_remove(struct pci_dev *dev); -extern int pcie_port_bus_register(void); +extern int __must_check pcie_port_bus_register(void); extern void pcie_port_bus_unregister(void); #endif /* _PORTDRV_H_ */ diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index bd6615b4d40..b20a9b81dae 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -6,7 +6,6 @@ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) */ -#include <linux/compiler.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> @@ -401,7 +400,7 @@ void pcie_port_device_remove(struct pci_dev *dev) pci_disable_msi(dev); } -int __must_check pcie_port_bus_register(void) +int pcie_port_bus_register(void) { return bus_register(&pcie_port_bus_type); } diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 037690e08f5..b4da7954611 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -37,7 +37,6 @@ static int pcie_portdrv_save_config(struct pci_dev *dev) return pci_save_state(dev); } -#ifdef CONFIG_PM static int pcie_portdrv_restore_config(struct pci_dev *dev) { int retval; @@ -50,6 +49,7 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) return 0; } +#ifdef CONFIG_PM static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) { int ret = pcie_port_device_suspend(dev, state); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3b0a5eb505..e159d660449 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1067,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL(pci_scan_single_device); EXPORT_SYMBOL_GPL(pci_scan_child_bus); #endif + +static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b) +{ + if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1; + else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1; + + if (a->bus->number < b->bus->number) return -1; + else if (a->bus->number > b->bus->number) return 1; + + if (a->devfn < b->devfn) return -1; + else if (a->devfn > b->devfn) return 1; + + return 0; +} + +/* + * Yes, this forcably breaks the klist abstraction temporarily. It + * just wants to sort the klist, not change reference counts and + * take/drop locks rapidly in the process. It does all this while + * holding the lock for the list, so objects can't otherwise be + * added/removed while we're swizzling. + */ +static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list) +{ + struct list_head *pos; + struct klist_node *n; + struct device *dev; + struct pci_dev *b; + + list_for_each(pos, list) { + n = container_of(pos, struct klist_node, n_node); + dev = container_of(n, struct device, knode_bus); + b = to_pci_dev(dev); + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node); + return; + } + } + list_move_tail(&a->dev.knode_bus.n_node, list); +} + +static void __init pci_sort_breadthfirst_klist(void) +{ + LIST_HEAD(sorted_devices); + struct list_head *pos, *tmp; + struct klist_node *n; + struct device *dev; + struct pci_dev *pdev; + + spin_lock(&pci_bus_type.klist_devices.k_lock); + list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { + n = container_of(pos, struct klist_node, n_node); + dev = container_of(n, struct device, knode_bus); + pdev = to_pci_dev(dev); + pci_insertion_sort_klist(pdev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); + spin_unlock(&pci_bus_type.klist_devices.k_lock); +} + +static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) +{ + struct pci_dev *b; + + list_for_each_entry(b, list, global_list) { + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->global_list, &b->global_list); + return; + } + } + list_move_tail(&a->global_list, list); +} + +static void __init pci_sort_breadthfirst_devices(void) +{ + LIST_HEAD(sorted_devices); + struct pci_dev *dev, *tmp; + + down_write(&pci_bus_sem); + list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) { + pci_insertion_sort_devices(dev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_devices); + up_write(&pci_bus_sem); +} + +void __init pci_sort_breadthfirst(void) +{ + pci_sort_breadthfirst_devices(); + pci_sort_breadthfirst_klist(); +} + diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 23b599d6a9d..5b448381169 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -453,6 +453,12 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) } 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 ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi ); /* * VIA ACPI: One IO region pointed to by longword at @@ -648,11 +654,43 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi * Some of the on-chip devices are actually '586 devices' so they are * listed here. */ + +static int via_irq_fixup_needed = -1; + +/* + * As some VIA hardware is available in PCI-card form, we need to restrict + * this quirk to VIA PCI hardware built onto VIA-based motherboards only. + * We try to locate a VIA southbridge before deciding whether the quirk + * should be applied. + */ +static const struct pci_device_id via_irq_fixup_tbl[] = { + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = PCI_CLASS_BRIDGE_ISA << 8, + .class_mask = 0xffff00, + }, + { 0, }, +}; + static void quirk_via_irq(struct pci_dev *dev) { u8 irq, new_irq; - new_irq = dev->irq & 0xf; + if (via_irq_fixup_needed == -1) + via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl); + + if (!via_irq_fixup_needed) + return; + + new_irq = dev->irq; + + /* Don't quirk interrupts outside the legacy IRQ range */ + if (!new_irq || new_irq > 15) + return; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); if (new_irq != irq) { printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n", @@ -661,14 +699,7 @@ static void quirk_via_irq(struct pci_dev *dev) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); /* * VIA VT82C598 has its device ID settable and many BIOSes @@ -683,33 +714,6 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id ); -#ifdef CONFIG_ACPI_SLEEP - -/* - * Some VIA systems boot with the abnormal status flag set. This can cause - * the BIOS to re-POST the system on resume rather than passing control - * back to the OS. Clear the flag on boot - */ -static void __devinit quirk_via_abnormal_poweroff(struct pci_dev *dev) -{ - u32 reg; - - acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, - ®); - - if (reg & 0x800) { - printk("Clearing abnormal poweroff flag\n"); - acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_STATUS, - (u16)0x800); - } -} - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_abnormal_poweroff); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_abnormal_poweroff); - -#endif - /* * CardBus controllers have a legacy base address that enables them * to respond as i82365 pcmcia controllers. We don't want them to @@ -1456,33 +1460,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); -/* - * Fixup the cardbus bridges on the IBM Dock II docking station - */ -static void __devinit quirk_ibm_dock2_cardbus(struct pci_dev *dev) -{ - u32 val; - - /* - * tie the 2 interrupt pins to INTA, and configure the - * multifunction routing register to handle this. - */ - if ((dev->subsystem_vendor == PCI_VENDOR_ID_IBM) && - (dev->subsystem_device == 0x0148)) { - printk(KERN_INFO "PCI: Found IBM Dock II Cardbus Bridge " - "applying quirk\n"); - pci_read_config_dword(dev, 0x8c, &val); - val = ((val & 0xffffff00) | 0x1002); - pci_write_config_dword(dev, 0x8c, val); - pci_read_config_dword(dev, 0x80, &val); - val = ((val & 0x00ffff00) | 0x2864c077); - pci_write_config_dword(dev, 0x80, val); - } -} - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, - quirk_ibm_dock2_cardbus); - static void __devinit quirk_netmos(struct pci_dev *dev) { unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4; @@ -1588,7 +1565,6 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); - static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { while (f < end) { @@ -1764,7 +1740,7 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) /* check HT MSI cap on this chipset and the root one. * a single one having MSI is enough to be sure that MSI are supported. */ - pdev = pci_find_slot(dev->bus->number, 0); + pdev = pci_get_slot(dev->bus, 0); if (dev->subordinate && !msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { printk(KERN_WARNING "PCI: MSI quirk detected. " @@ -1772,6 +1748,7 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) pci_name(dev)); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } + pci_dev_put(pdev); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index f5ee7ce16fa..e1dcefc69bb 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -71,7 +71,11 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) void __iomem *image; int last_image; - /* IORESOURCE_ROM_SHADOW only set on x86 */ + /* + * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy + * memory map if the VGA enable bit of the Bridge Control register is + * set for embedded VGA. + */ if (res->flags & IORESOURCE_ROM_SHADOW) { /* primary video rom always starts here */ start = (loff_t)0xC0000; diff --git a/drivers/pci/search.c b/drivers/pci/search.c index d529462d1b5..2f13eba5d5a 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -140,6 +140,31 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) } /** + * pci_get_bus_and_slot - locate PCI device from a given PCI slot + * @bus: number of PCI bus on which desired PCI device resides + * @devfn: encodes number of PCI slot in which the desired PCI + * device resides and the logical device number within that slot + * in case of multi-function devices. + * + * Given a PCI bus and slot/function number, the desired PCI device + * is located in system global list of PCI devices. If the device + * is found, a pointer to its data structure is returned. If no + * device is found, %NULL is returned. The returned device has its + * reference count bumped by one. + */ + +struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) +{ + struct pci_dev *dev = NULL; + + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (dev->bus->number == bus && dev->devfn == devfn) + return dev; + } + return NULL; +} + +/** * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids @@ -274,6 +299,45 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); } +/** + * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @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_get_device. + * If a PCI device is 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 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. + */ +struct pci_dev * +pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(in_interrupt()); + down_read(&pci_bus_sem); + n = from ? from->global_list.prev : pci_devices.prev; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device)) + goto exit; + n = n->prev; + } + dev = NULL; +exit: + dev = pci_dev_get(dev); + up_read(&pci_bus_sem); + pci_dev_put(from); + return dev; +} /** * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id @@ -382,12 +446,16 @@ exit: } EXPORT_SYMBOL(pci_dev_present); -EXPORT_SYMBOL(pci_find_bus); -EXPORT_SYMBOL(pci_find_next_bus); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); +/* For boot time work */ +EXPORT_SYMBOL(pci_find_bus); +EXPORT_SYMBOL(pci_find_next_bus); +/* For everyone */ EXPORT_SYMBOL(pci_get_device); +EXPORT_SYMBOL(pci_get_device_reverse); EXPORT_SYMBOL(pci_get_subsys); EXPORT_SYMBOL(pci_get_slot); +EXPORT_SYMBOL(pci_get_bus_and_slot); EXPORT_SYMBOL(pci_get_class); diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 7f5df9a9f39..3bcb7dc3299 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -241,12 +241,6 @@ static int __init at91_cf_probe(struct platform_device *pdev) csa = at91_sys_read(AT91_EBI_CSA); at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH); - /* force poweron defaults for these pins ... */ - (void) at91_set_A_periph(AT91_PIN_PC9, 0); /* A25/CFRNW */ - (void) at91_set_A_periph(AT91_PIN_PC10, 0); /* NCS4/CFCS */ - (void) at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS5/CFCE1 */ - (void) at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */ - /* nWAIT is _not_ a default setting */ (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */ @@ -316,12 +310,14 @@ static int __init at91_cf_probe(struct platform_device *pdev) return 0; fail2: - iounmap((void __iomem *) cf->socket.io_offset); release_mem_region(io->start, io->end + 1 - io->start); fail1: + if (cf->socket.io_offset) + iounmap((void __iomem *) cf->socket.io_offset); if (board->irq_pin) free_irq(board->irq_pin, cf); fail0a: + device_init_wakeup(&pdev->dev, 0); free_irq(board->det_pin, cf); device_init_wakeup(&pdev->dev, 0); fail0: @@ -360,26 +356,20 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) struct at91_cf_data *board = cf->board; pcmcia_socket_dev_suspend(&pdev->dev, mesg); - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(board->det_pin); - else { + if (board->irq_pin) + enable_irq_wake(board->irq_pin); + } else { disable_irq_wake(board->det_pin); - disable_irq(board->det_pin); + if (board->irq_pin) + disable_irq_wake(board->irq_pin); } - if (board->irq_pin) - disable_irq(board->irq_pin); return 0; } static int at91_cf_resume(struct platform_device *pdev) { - struct at91_cf_socket *cf = platform_get_drvdata(pdev); - struct at91_cf_data *board = cf->board; - - if (board->irq_pin) - enable_irq(board->irq_pin); - if (!device_may_wakeup(&pdev->dev)) - enable_irq(board->det_pin); pcmcia_socket_dev_resume(&pdev->dev); return 0; } diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index d5dd0ce6553..551bde5d943 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -351,6 +351,7 @@ struct skt_dev_info { int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) { struct skt_dev_info *sinfo; + struct au1000_pcmcia_socket *skt; int ret, i; sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL); @@ -365,7 +366,7 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, * Initialise the per-socket structure. */ for (i = 0; i < nr; i++) { - struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); + skt = PCMCIA_SOCKET(i); memset(skt, 0, sizeof(*skt)); skt->socket.resource_ops = &pccard_static_ops; @@ -438,17 +439,29 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, dev_set_drvdata(dev, sinfo); return 0; - do { - struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); + +out_err: + flush_scheduled_work(); + ops->hw_shutdown(skt); + while (i-- > 0) { + skt = PCMCIA_SOCKET(i); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); -out_err: flush_scheduled_work(); + if (i == 0) { + iounmap(skt->virt_io + (u32)mips_io_port_base); + skt->virt_io = NULL; + } +#ifndef CONFIG_MIPS_XXS1500 + else { + iounmap(skt->virt_io + (u32)mips_io_port_base); + skt->virt_io = NULL; + } +#endif ops->hw_shutdown(skt); - i--; - } while (i > 0); + } kfree(sinfo); out: return ret; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 74b3124e824..a20d84d707d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -717,6 +717,7 @@ static int pcmcia_requery(struct device *dev, void * _data) static void pcmcia_bus_rescan(struct pcmcia_socket *skt) { int no_devices=0; + int ret = 0; unsigned long flags; /* must be called with skt_mutex held */ @@ -729,7 +730,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt) * missing resource information or other trouble, we need to * do this now. */ if (no_devices) { - int ret = pcmcia_card_add(skt); + ret = pcmcia_card_add(skt); if (ret) return; } @@ -741,7 +742,9 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt) /* we re-scan all devices, not just the ones connected to this * socket. This does not matter, though. */ - bus_rescan_devices(&pcmcia_bus_type); + ret = bus_rescan_devices(&pcmcia_bus_type); + if (ret) + printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n"); } static inline int pcmcia_devmatch(struct pcmcia_device *dev, @@ -1001,6 +1004,7 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + int ret; if (!count) return -EINVAL; @@ -1009,7 +1013,10 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, p_dev->allow_func_id_match = 1; mutex_unlock(&p_dev->socket->skt_mutex); - bus_rescan_devices(&pcmcia_bus_type); + ret = bus_rescan_devices(&pcmcia_bus_type); + if (ret) + printk(KERN_INFO "pcmcia: bus_rescan_devices failed after " + "allowing func_id matches\n"); return count; } @@ -1264,6 +1271,9 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev, socket->pcmcia_state.dead = 1; pccard_register_pcmcia(socket, NULL); + /* unregister any unbound devices */ + pcmcia_card_remove(socket, NULL); + pcmcia_put_socket(socket); return; @@ -1292,10 +1302,22 @@ struct bus_type pcmcia_bus_type = { static int __init init_pcmcia_bus(void) { + int ret; + spin_lock_init(&pcmcia_dev_list_lock); - bus_register(&pcmcia_bus_type); - class_interface_register(&pcmcia_bus_interface); + ret = bus_register(&pcmcia_bus_type); + if (ret < 0) { + printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret); + return ret; + } + ret = class_interface_register(&pcmcia_bus_interface); + if (ret < 0) { + printk(KERN_WARNING + "pcmcia: class_interface_register error: %d\n", ret); + bus_unregister(&pcmcia_bus_type); + return ret; + } pcmcia_setup_ioctl(); diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 82715f44895..c2ea07aa7a1 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -41,6 +41,7 @@ static struct pci_device_id i82092aa_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids); +#ifdef CONFIG_PM static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state) { return pcmcia_socket_dev_suspend(&dev->dev, state); @@ -50,14 +51,17 @@ static int i82092aa_socket_resume (struct pci_dev *dev) { return pcmcia_socket_dev_resume(&dev->dev); } +#endif static struct pci_driver i82092aa_pci_drv = { .name = "i82092aa", .id_table = i82092aa_pci_ids, .probe = i82092aa_pci_probe, .remove = __devexit_p(i82092aa_pci_remove), +#ifdef CONFIG_PM .suspend = i82092aa_socket_suspend, .resume = i82092aa_socket_resume, +#endif }; @@ -705,10 +709,7 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_ static int i82092aa_module_init(void) { - enter("i82092aa_module_init"); - pci_register_driver(&i82092aa_pci_drv); - leave("i82092aa_module_init"); - return 0; + return pci_register_driver(&i82092aa_pci_drv); } static void i82092aa_module_exit(void) diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index e070a289676..3b72be88040 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -427,7 +427,7 @@ static int voltage_set(int slot, int vcc, int vpp) reg |= BCSR1_PCCVCC1; break; default: - return 1; + goto out_unmap; } switch(vpp) { @@ -438,15 +438,15 @@ static int voltage_set(int slot, int vcc, int vpp) if(vcc == vpp) reg |= BCSR1_PCCVPP1; else - return 1; + goto out_unmap; break; case 120: if ((vcc == 33) || (vcc == 50)) reg |= BCSR1_PCCVPP0; else - return 1; + goto out_unmap; default: - return 1; + goto out_unmap; } /* first, turn off all power */ @@ -457,6 +457,10 @@ static int voltage_set(int slot, int vcc, int vpp) iounmap(bcsr_io); return 0; + +out_unmap: + iounmap(bcsr_io); + return 1; } #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index c8e838c6976..06bf7f48836 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -309,9 +309,10 @@ static int __devinit omap_cf_probe(struct device *dev) return 0; fail2: - iounmap((void __iomem *) cf->socket.io_offset); release_mem_region(cf->phys_cf, SZ_8K); fail1: + if (cf->socket.io_offset) + iounmap((void __iomem *) cf->socket.io_offset); free_irq(irq, cf); fail0: kfree(cf); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 9ad18e62658..310ede575ca 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -128,9 +128,12 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, int count, int *eof, void *data) { char *p = buf; + int rc; - bus_for_each_drv(&pcmcia_bus_type, NULL, - (void *) &p, proc_read_drivers_callback); + rc = bus_for_each_drv(&pcmcia_bus_type, NULL, + (void *) &p, proc_read_drivers_callback); + if (rc < 0) + return rc; return (p - buf); } @@ -269,8 +272,10 @@ rescan: * Prevent this racing with a card insertion. */ mutex_lock(&s->skt_mutex); - bus_rescan_devices(&pcmcia_bus_type); + ret = bus_rescan_devices(&pcmcia_bus_type); mutex_unlock(&s->skt_mutex); + if (ret) + goto err_put_module; /* check whether the driver indeed matched. I don't care if this * is racy or not, because it can only happen on cardmgr access diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 74cebd42403..b9201c2ec38 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -95,7 +95,7 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, * potential conflicts, just the most obvious ones. */ for (i = 0; i < MAX_IO_WIN; i++) - if ((s->io[i].res) && + if ((s->io[i].res) && *base && ((s->io[i].res->start & (align-1)) == *base)) return 1; for (i = 0; i < MAX_IO_WIN; i++) { diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index c83a0a6b158..a70f97fdbbd 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -755,6 +755,7 @@ static void __devexit pd6729_pci_remove(struct pci_dev *dev) kfree(socket); } +#ifdef CONFIG_PM static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state) { return pcmcia_socket_dev_suspend(&dev->dev, state); @@ -764,6 +765,7 @@ static int pd6729_socket_resume(struct pci_dev *dev) { return pcmcia_socket_dev_resume(&dev->dev); } +#endif static struct pci_device_id pd6729_pci_ids[] = { { @@ -781,8 +783,10 @@ static struct pci_driver pd6729_pci_drv = { .id_table = pd6729_pci_ids, .probe = pd6729_pci_probe, .remove = __devexit_p(pd6729_pci_remove), +#ifdef CONFIG_PM .suspend = pd6729_socket_suspend, .resume = pd6729_socket_resume, +#endif }; static int pd6729_module_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index b3518131ea0..dca9f8549b3 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -166,7 +166,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, } #endif -int pxa2xx_drv_pcmcia_probe(struct device *dev) +int __pxa2xx_drv_pcmcia_probe(struct device *dev) { int ret; struct pcmcia_low_level *ops; @@ -203,35 +203,52 @@ int pxa2xx_drv_pcmcia_probe(struct device *dev) return ret; } -EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); +EXPORT_SYMBOL(__pxa2xx_drv_pcmcia_probe); -static int pxa2xx_drv_pcmcia_resume(struct device *dev) + +static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) +{ + return __pxa2xx_drv_pcmcia_probe(&dev->dev); +} + +static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) +{ + return soc_common_drv_pcmcia_remove(&dev->dev); +} + +static int pxa2xx_drv_pcmcia_suspend(struct platform_device *dev, pm_message_t state) +{ + return pcmcia_socket_dev_suspend(&dev->dev, state); +} + +static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev) { - struct pcmcia_low_level *ops = dev->platform_data; + struct pcmcia_low_level *ops = dev->dev.platform_data; int nr = ops ? ops->nr : 0; MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); - return pcmcia_socket_dev_resume(dev); + return pcmcia_socket_dev_resume(&dev->dev); } -static struct device_driver pxa2xx_pcmcia_driver = { +static struct platform_driver pxa2xx_pcmcia_driver = { .probe = pxa2xx_drv_pcmcia_probe, - .remove = soc_common_drv_pcmcia_remove, - .suspend = pcmcia_socket_dev_suspend, + .remove = pxa2xx_drv_pcmcia_remove, + .suspend = pxa2xx_drv_pcmcia_suspend, .resume = pxa2xx_drv_pcmcia_resume, - .name = "pxa2xx-pcmcia", - .bus = &platform_bus_type, + .driver = { + .name = "pxa2xx-pcmcia", + }, }; static int __init pxa2xx_pcmcia_init(void) { - return driver_register(&pxa2xx_pcmcia_driver); + return platform_driver_register(&pxa2xx_pcmcia_driver); } static void __exit pxa2xx_pcmcia_exit(void) { - driver_unregister(&pxa2xx_pcmcia_driver); + platform_driver_unregister(&pxa2xx_pcmcia_driver); } fs_initcall(pxa2xx_pcmcia_init); diff --git a/drivers/pcmcia/pxa2xx_base.h b/drivers/pcmcia/pxa2xx_base.h index e46cff345d4..235d681652c 100644 --- a/drivers/pcmcia/pxa2xx_base.h +++ b/drivers/pcmcia/pxa2xx_base.h @@ -1,3 +1,3 @@ /* temporary measure */ -extern int pxa2xx_drv_pcmcia_probe(struct device *); +extern int __pxa2xx_drv_pcmcia_probe(struct device *); diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index fd1f691c7c2..a92f11143c4 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -260,7 +260,7 @@ int __init pcmcia_lubbock_init(struct sa1111_dev *sadev) lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); sadev->dev.platform_data = &lubbock_pcmcia_ops; - ret = pxa2xx_drv_pcmcia_probe(&sadev->dev); + ret = __pxa2xx_drv_pcmcia_probe(&sadev->dev); } return ret; diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 3627e52e0c2..e433704e026 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -824,3 +824,4 @@ int soc_common_drv_pcmcia_remove(struct device *dev) return 0; } +EXPORT_SYMBOL(soc_common_drv_pcmcia_remove); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 26229d9da76..da471bddc97 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1197,8 +1197,12 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i ret = pcmcia_register_socket(&socket->socket); if (ret == 0) { /* Add the yenta register attributes */ - device_create_file(&dev->dev, &dev_attr_yenta_registers); - goto out; + ret = device_create_file(&dev->dev, &dev_attr_yenta_registers); + if (ret == 0) + goto out; + + /* error path... */ + pcmcia_unregister_socket(&socket->socket); } unmap: @@ -1213,7 +1217,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i return ret; } - +#ifdef CONFIG_PM static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state) { struct yenta_socket *socket = pci_get_drvdata(dev); @@ -1248,12 +1252,18 @@ static int yenta_dev_resume (struct pci_dev *dev) struct yenta_socket *socket = pci_get_drvdata(dev); if (socket) { + int rc; + pci_set_power_state(dev, 0); /* FIXME: pci_restore_state needs to have a better interface */ pci_restore_state(dev); pci_write_config_dword(dev, 16*4, socket->saved_state[0]); pci_write_config_dword(dev, 17*4, socket->saved_state[1]); - pci_enable_device(dev); + + rc = pci_enable_device(dev); + if (rc) + return rc; + pci_set_master(dev); if (socket->type && socket->type->restore_state) @@ -1262,7 +1272,7 @@ static int yenta_dev_resume (struct pci_dev *dev) return pcmcia_socket_dev_resume(&dev->dev); } - +#endif #define CB_ID(vend,dev,type) \ { \ @@ -1359,8 +1369,10 @@ static struct pci_driver yenta_cardbus_driver = { .id_table = yenta_table, .probe = yenta_probe, .remove = __devexit_p(yenta_close), +#ifdef CONFIG_PM .suspend = yenta_dev_suspend, .resume = yenta_dev_resume, +#endif }; diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index dc79b0a0059..379048fdf05 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -776,21 +776,32 @@ static void pnpacpi_encode_dma(struct acpi_resource *resource, struct resource *p) { /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ - if (p->flags & IORESOURCE_DMA_COMPATIBLE) - resource->data.dma.type = ACPI_COMPATIBILITY; - else if (p->flags & IORESOURCE_DMA_TYPEA) - resource->data.dma.type = ACPI_TYPE_A; - else if (p->flags & IORESOURCE_DMA_TYPEB) - resource->data.dma.type = ACPI_TYPE_B; - else if (p->flags & IORESOURCE_DMA_TYPEF) - resource->data.dma.type = ACPI_TYPE_F; - if (p->flags & IORESOURCE_DMA_8BIT) - resource->data.dma.transfer = ACPI_TRANSFER_8; - else if (p->flags & IORESOURCE_DMA_8AND16BIT) - resource->data.dma.transfer = ACPI_TRANSFER_8_16; - else if (p->flags & IORESOURCE_DMA_16BIT) - resource->data.dma.transfer = ACPI_TRANSFER_16; - resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER; + switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { + case IORESOURCE_DMA_TYPEA: + resource->data.dma.type = ACPI_TYPE_A; + break; + case IORESOURCE_DMA_TYPEB: + resource->data.dma.type = ACPI_TYPE_B; + break; + case IORESOURCE_DMA_TYPEF: + resource->data.dma.type = ACPI_TYPE_F; + break; + default: + resource->data.dma.type = ACPI_COMPATIBILITY; + } + + switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { + case IORESOURCE_DMA_8BIT: + resource->data.dma.transfer = ACPI_TRANSFER_8; + break; + case IORESOURCE_DMA_8AND16BIT: + resource->data.dma.transfer = ACPI_TRANSFER_8_16; + break; + default: + resource->data.dma.transfer = ACPI_TRANSFER_16; + } + + resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); resource->data.dma.channel_count = 1; resource->data.dma.channels[0] = p->start; } diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 0b20dfacbf5..d9417072807 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -136,7 +136,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) dt->tm_min = BCD2BIN(chip->buf[2]); dt->tm_hour = BCD2BIN(chip->buf[3]); dt->tm_mday = BCD2BIN(chip->buf[4]); - dt->tm_mon = BCD2BIN(chip->buf[5] - 1); + dt->tm_mon = BCD2BIN(chip->buf[5]) - 1; dt->tm_wday = BCD2BIN(chip->buf[6]); dt->tm_year = BCD2BIN(chip->buf[7]); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 8b6efcc0505..143302a8e79 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -160,7 +160,7 @@ static int sh_rtc_open(struct device *dev) tmp |= RCR1_CIE; writeb(tmp, rtc->regbase + RCR1); - ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT, + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, "sh-rtc period", dev); if (unlikely(ret)) { dev_err(dev, "request period IRQ failed with %d, IRQ %d\n", @@ -168,7 +168,7 @@ static int sh_rtc_open(struct device *dev) return ret; } - ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT, + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, "sh-rtc carry", dev); if (unlikely(ret)) { dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", @@ -177,7 +177,7 @@ static int sh_rtc_open(struct device *dev) goto err_bad_carry; } - ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT, + ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, IRQF_DISABLED, "sh-rtc alarm", dev); if (unlikely(ret)) { dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 09b714f1cdc..3b58d3d5d38 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -195,9 +195,9 @@ static int rtc_probe(struct platform_device *pdev) * are all disabled */ v3020_set_reg(chip, V3020_STATUS_0, 0x0); - dev_info(&pdev->dev, "Chip available at physical address 0x%p," + dev_info(&pdev->dev, "Chip available at physical address 0x%llx," "data connected to D%d\n", - (void*)pdev->resource[0].start, + (unsigned long long)pdev->resource[0].start, chip->leftshift); platform_set_drvdata(pdev, chip); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d0647d116ea..79ffef6bfaf 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -203,6 +203,7 @@ dasd_state_basic_to_known(struct dasd_device * device) rc = dasd_flush_ccw_queue(device, 1); if (rc) return rc; + dasd_clear_timer(device); DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); if (device->debug_area != NULL) { diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 4362ff26024..b9b0fc3f812 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -73,12 +73,15 @@ static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, struct mon_buf *entry, *next; list_for_each_entry_safe(entry, next, &monpriv->list, list) - if (entry->hdr.applid == monhdr->applid && + if ((entry->hdr.mon_function == monhdr->mon_function || + monhdr->mon_function == MONWRITE_STOP_INTERVAL) && + entry->hdr.applid == monhdr->applid && entry->hdr.record_num == monhdr->record_num && entry->hdr.version == monhdr->version && entry->hdr.release == monhdr->release && entry->hdr.mod_level == monhdr->mod_level) return entry; + return NULL; } @@ -92,7 +95,9 @@ static int monwrite_new_hdr(struct mon_private *monpriv) monhdr->mon_function > MONWRITE_START_CONFIG || monhdr->hdrlen != sizeof(struct monwrite_hdr)) return -EINVAL; - monbuf = monwrite_find_hdr(monpriv, monhdr); + monbuf = NULL; + if (monhdr->mon_function != MONWRITE_GEN_EVENT) + monbuf = monwrite_find_hdr(monpriv, monhdr); if (monbuf) { if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) { monhdr->datalen = monbuf->hdr.datalen; @@ -104,13 +109,13 @@ static int monwrite_new_hdr(struct mon_private *monpriv) kfree(monbuf); monbuf = NULL; } - } else { + } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) { if (mon_buf_count >= mon_max_bufs) return -ENOSPC; monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL); if (!monbuf) return -ENOMEM; - monbuf->data = kzalloc(monbuf->hdr.datalen, + monbuf->data = kzalloc(monhdr->datalen, GFP_KERNEL | GFP_DMA); if (!monbuf->data) { kfree(monbuf); @@ -118,7 +123,8 @@ static int monwrite_new_hdr(struct mon_private *monpriv) } monbuf->hdr = *monhdr; list_add_tail(&monbuf->list, &monpriv->list); - mon_buf_count++; + if (monhdr->mon_function != MONWRITE_GEN_EVENT) + mon_buf_count++; } monpriv->current_buf = monbuf; return 0; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 07c7f19339d..2d78f0f4a40 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -370,7 +370,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) struct res_acc_data *res_data; struct subchannel *sch; - res_data = (struct res_acc_data *)data; + res_data = data; sch = get_subchannel_by_schid(schid); if (!sch) /* Check if a subchannel is newly available. */ @@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data) u32 isinfo[28]; } *lir; - lir = (struct lir*) data; + lir = data; if (!(lir->iq&0x80)) /* NULL link incident record */ return -EINVAL; @@ -628,7 +628,7 @@ __chp_add(struct subchannel_id schid, void *data) struct channel_path *chp; struct subchannel *sch; - chp = (struct channel_path *)data; + chp = data; sch = get_subchannel_by_schid(schid); if (!sch) /* Check if the subchannel is now available. */ @@ -707,8 +707,7 @@ chp_process_crw(int chpid, int on) return chp_add(chpid); } -static inline int -__check_for_io_and_kill(struct subchannel *sch, int index) +static inline int check_for_io_on_path(struct subchannel *sch, int index) { int cc; @@ -718,10 +717,8 @@ __check_for_io_and_kill(struct subchannel *sch, int index) cc = stsch(sch->schid, &sch->schib); if (cc) return 0; - if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) { - device_set_waiting(sch); + if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) return 1; - } return 0; } @@ -750,12 +747,10 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) } else { sch->opm &= ~(0x80 >> chp); sch->lpm &= ~(0x80 >> chp); - /* - * Give running I/O a grace period in which it - * can successfully terminate, even using the - * just varied off path. Then kill it. - */ - if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) { + if (check_for_io_on_path(sch, chp)) + /* Path verification is done after killing. */ + device_kill_io(sch); + else if (!sch->lpm) { if (css_enqueue_subchannel_slow(sch->schid)) { css_clear_subchannel_slow_list(); need_rescan = 1; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f18b1623cad..8936e460a80 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -609,8 +609,8 @@ do_IRQ (struct pt_regs *regs) struct irb *irb; struct pt_regs *old_regs; - irq_enter (); old_regs = set_irq_regs(regs); + irq_enter(); asm volatile ("mc 0,0"); if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) /** @@ -655,8 +655,8 @@ do_IRQ (struct pt_regs *regs) * out of the sie which costs more cycles than it saves. */ } while (!MACHINE_IS_VM && tpi (NULL) != 0); + irq_exit(); set_irq_regs(old_regs); - irq_exit (); } #ifdef CONFIG_CCW_CONSOLE diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 7086a74e987..ad7f7e1c016 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -177,7 +177,7 @@ get_subchannel_by_schid(struct subchannel_id schid) struct device *dev; dev = bus_find_device(&css_bus_type, NULL, - (void *)&schid, check_subchannel); + &schid, check_subchannel); return dev ? to_subchannel(dev) : NULL; } @@ -271,10 +271,6 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) /* Reset intparm to zeroes. */ sch->schib.pmcw.intparm = 0; cio_modify(sch); - - /* Probe if necessary. */ - if (action == UNREGISTER_PROBE) - ret = css_probe_device(sch->schid); break; case REPROBE: device_trigger_reprobe(sch); @@ -283,6 +279,9 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) break; } spin_unlock_irqrestore(&sch->lock, flags); + /* Probe if necessary. */ + if (action == UNREGISTER_PROBE) + ret = css_probe_device(sch->schid); return ret; } diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 8aabb4adeb5..4c2ff833628 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -76,9 +76,8 @@ struct ccw_device_private { int state; /* device state */ atomic_t onoff; unsigned long registered; - __u16 devno; /* device number */ - __u16 sch_no; /* subchannel number */ - __u8 ssid; /* subchannel set id */ + struct ccw_dev_id dev_id; /* device id */ + struct subchannel_id schid; /* subchannel number */ __u8 imask; /* lpm mask for SNID/SID/SPGID */ int iretry; /* retry counter SNID/SID/SPGID */ struct { @@ -171,7 +170,7 @@ void device_trigger_reprobe(struct subchannel *); /* Helper functions for vary on/off. */ int device_is_online(struct subchannel *); -void device_set_waiting(struct subchannel *); +void device_kill_io(struct subchannel *); /* Machine check helper function. */ void device_kill_pending_timer(struct subchannel *); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 688945662c1..39c98f94050 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -532,8 +532,7 @@ device_remove_files(struct device *dev) /* this is a simple abstraction for device_register that sets the * correct bus type and adds the bus specific files */ -int -ccw_device_register(struct ccw_device *cdev) +static int ccw_device_register(struct ccw_device *cdev) { struct device *dev = &cdev->dev; int ret; @@ -552,21 +551,19 @@ ccw_device_register(struct ccw_device *cdev) } struct match_data { - unsigned int devno; - unsigned int ssid; + struct ccw_dev_id dev_id; struct ccw_device * sibling; }; static int match_devno(struct device * dev, void * data) { - struct match_data * d = (struct match_data *)data; + struct match_data * d = data; struct ccw_device * cdev; cdev = to_ccwdev(dev); if ((cdev->private->state == DEV_STATE_DISCONNECTED) && - (cdev->private->devno == d->devno) && - (cdev->private->ssid == d->ssid) && + ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) && (cdev != d->sibling)) { cdev->private->state = DEV_STATE_NOT_OPER; return 1; @@ -574,15 +571,13 @@ match_devno(struct device * dev, void * data) return 0; } -static struct ccw_device * -get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid, - struct ccw_device *sibling) +static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id, + struct ccw_device *sibling) { struct device *dev; struct match_data data; - data.devno = devno; - data.ssid = ssid; + data.dev_id = *dev_id; data.sibling = sibling; dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno); @@ -595,7 +590,7 @@ ccw_device_add_changed(void *data) struct ccw_device *cdev; - cdev = (struct ccw_device *)data; + cdev = data; if (device_add(&cdev->dev)) { put_device(&cdev->dev); return; @@ -616,9 +611,9 @@ ccw_device_do_unreg_rereg(void *data) struct subchannel *sch; int need_rename; - cdev = (struct ccw_device *)data; + cdev = data; sch = to_subchannel(cdev->dev.parent); - if (cdev->private->devno != sch->schib.pmcw.dev) { + if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) { /* * The device number has changed. This is usually only when * a device has been detached under VM and then re-appeared @@ -633,10 +628,12 @@ ccw_device_do_unreg_rereg(void *data) * get possibly sick... */ struct ccw_device *other_cdev; + struct ccw_dev_id dev_id; need_rename = 1; - other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev, - sch->schid.ssid, cdev); + dev_id.devno = sch->schib.pmcw.dev; + dev_id.ssid = sch->schid.ssid; + other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev); if (other_cdev) { struct subchannel *other_sch; @@ -652,7 +649,7 @@ ccw_device_do_unreg_rereg(void *data) } /* Update ssd info here. */ css_get_ssd_info(sch); - cdev->private->devno = sch->schib.pmcw.dev; + cdev->private->dev_id.devno = sch->schib.pmcw.dev; } else need_rename = 0; device_remove_files(&cdev->dev); @@ -662,7 +659,7 @@ ccw_device_do_unreg_rereg(void *data) snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", sch->schid.ssid, sch->schib.pmcw.dev); PREPARE_WORK(&cdev->private->kick_work, - ccw_device_add_changed, (void *)cdev); + ccw_device_add_changed, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } @@ -687,7 +684,7 @@ io_subchannel_register(void *data) int ret; unsigned long flags; - cdev = (struct ccw_device *) data; + cdev = data; sch = to_subchannel(cdev->dev.parent); if (klist_node_attached(&cdev->dev.knode_parent)) { @@ -759,7 +756,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) break; sch = to_subchannel(cdev->dev.parent); PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister, (void *) cdev); + ccw_device_call_sch_unregister, cdev); queue_work(slow_path_wq, &cdev->private->kick_work); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); @@ -774,7 +771,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) if (!get_device(&cdev->dev)) break; PREPARE_WORK(&cdev->private->kick_work, - io_subchannel_register, (void *) cdev); + io_subchannel_register, cdev); queue_work(slow_path_wq, &cdev->private->kick_work); break; } @@ -792,9 +789,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) /* Init private data. */ priv = cdev->private; - priv->devno = sch->schib.pmcw.dev; - priv->ssid = sch->schid.ssid; - priv->sch_no = sch->schid.sch_no; + priv->dev_id.devno = sch->schib.pmcw.dev; + priv->dev_id.ssid = sch->schid.ssid; + priv->schid = sch->schid; priv->state = DEV_STATE_NOT_OPER; INIT_LIST_HEAD(&priv->cmb_list); init_waitqueue_head(&priv->wait_q); @@ -912,7 +909,7 @@ io_subchannel_remove (struct subchannel *sch) */ if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_unregister, (void *) cdev); + ccw_device_unregister, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } return 0; @@ -1055,7 +1052,7 @@ __ccwdev_check_busid(struct device *dev, void *id) { char *bus_id; - bus_id = (char *)id; + bus_id = id; return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0); } diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 00be9a5b4ac..9233b5c0bcc 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -21,7 +21,6 @@ enum dev_state { /* states to wait for i/o completion before doing something */ DEV_STATE_CLEAR_VERIFY, DEV_STATE_TIMEOUT_KILL, - DEV_STATE_WAIT4IO, DEV_STATE_QUIESCE, /* special states for devices gone not operational */ DEV_STATE_DISCONNECTED, @@ -79,7 +78,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); -int ccw_device_register(struct ccw_device *); void ccw_device_do_unreg_rereg(void *); void ccw_device_call_sch_unregister(void *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index b67620208f3..de3d0857db9 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -59,18 +59,6 @@ device_set_disconnected(struct subchannel *sch) cdev->private->state = DEV_STATE_DISCONNECTED; } -void -device_set_waiting(struct subchannel *sch) -{ - struct ccw_device *cdev; - - if (!sch->dev.driver_data) - return; - cdev = sch->dev.driver_data; - ccw_device_set_timeout(cdev, 10*HZ); - cdev->private->state = DEV_STATE_WAIT4IO; -} - /* * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. */ @@ -183,9 +171,9 @@ ccw_device_handle_oper(struct ccw_device *cdev) cdev->id.cu_model != cdev->private->senseid.cu_model || cdev->id.dev_type != cdev->private->senseid.dev_type || cdev->id.dev_model != cdev->private->senseid.dev_model || - cdev->private->devno != sch->schib.pmcw.dev) { + cdev->private->dev_id.devno != sch->schib.pmcw.dev) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_do_unreg_rereg, (void *)cdev); + ccw_device_do_unreg_rereg, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); return 0; } @@ -255,7 +243,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) case DEV_STATE_NOT_OPER: CIO_DEBUG(KERN_WARNING, 2, "SenseID : unknown device %04x on subchannel " - "0.%x.%04x\n", cdev->private->devno, + "0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: @@ -282,14 +270,15 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: " "CU Type/Mod = %04X/%02X, Dev Type/Mod = " "%04X/%02X\n", - cdev->private->ssid, cdev->private->devno, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, cdev->id.cu_type, cdev->id.cu_model, cdev->id.dev_type, cdev->id.dev_model); break; case DEV_STATE_BOXED: CIO_DEBUG(KERN_WARNING, 2, "SenseID : boxed device %04x on subchannel " - "0.%x.%04x\n", cdev->private->devno, + "0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); break; } @@ -325,13 +314,13 @@ ccw_device_oper_notify(void *data) struct subchannel *sch; int ret; - cdev = (struct ccw_device *)data; + cdev = data; sch = to_subchannel(cdev->dev.parent); ret = (sch->driver && sch->driver->notify) ? sch->driver->notify(&sch->dev, CIO_OPER) : 0; if (!ret) /* Driver doesn't want device back. */ - ccw_device_do_unreg_rereg((void *)cdev); + ccw_device_do_unreg_rereg(cdev); else { /* Reenable channel measurements, if needed. */ cmf_reenable(cdev); @@ -363,12 +352,12 @@ ccw_device_done(struct ccw_device *cdev, int state) if (state == DEV_STATE_BOXED) CIO_DEBUG(KERN_WARNING, 2, "Boxed device %04x on subchannel %04x\n", - cdev->private->devno, sch->schid.sch_no); + cdev->private->dev_id.devno, sch->schid.sch_no); if (cdev->private->flags.donotify) { cdev->private->flags.donotify = 0; PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify, - (void *)cdev); + cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } wake_up(&cdev->private->wait_q); @@ -412,7 +401,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev) /* PGID mismatch, can't pathgroup. */ CIO_MSG_EVENT(0, "SNID - pgid mismatch for device " "0.%x.%04x, can't pathgroup\n", - cdev->private->ssid, cdev->private->devno); + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); cdev->private->options.pgroup = 0; return; } @@ -523,7 +513,7 @@ ccw_device_nopath_notify(void *data) struct subchannel *sch; int ret; - cdev = (struct ccw_device *)data; + cdev = data; sch = to_subchannel(cdev->dev.parent); /* Extra sanity. */ if (sch->lpm) @@ -537,7 +527,7 @@ ccw_device_nopath_notify(void *data) if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister, - (void *)cdev); + cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } else @@ -588,11 +578,15 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) } break; case -ETIME: + /* Reset oper notify indication after verify error. */ + cdev->private->flags.donotify = 0; ccw_device_done(cdev, DEV_STATE_BOXED); break; default: + /* Reset oper notify indication after verify error. */ + cdev->private->flags.donotify = 0; PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; @@ -723,7 +717,7 @@ ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister, (void *)cdev); + ccw_device_call_sch_unregister, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } wake_up(&cdev->private->wait_q); @@ -754,7 +748,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) } if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister, (void *)cdev); + ccw_device_call_sch_unregister, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } wake_up(&cdev->private->wait_q); @@ -859,7 +853,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else @@ -885,7 +879,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) /* Basic sense hasn't started. Try again. */ ccw_device_do_sense(cdev, irb); else { - printk("Huh? %s(%s): unsolicited interrupt...\n", + printk(KERN_INFO "Huh? %s(%s): unsolicited " + "interrupt...\n", __FUNCTION__, cdev->dev.bus_id); if (cdev->handler) cdev->handler (cdev, 0, irb); @@ -944,10 +939,10 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-ETIMEDOUT)); + ERR_PTR(-EIO)); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else if (cdev->private->flags.doverify) /* Start delayed path verification. */ @@ -970,7 +965,7 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else @@ -981,51 +976,15 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-ETIMEDOUT)); -} - -static void -ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event) -{ - struct irb *irb; - struct subchannel *sch; - - irb = (struct irb *) __LC_IRB; - /* - * Accumulate status and find out if a basic sense is needed. - * This is fine since we have already adapted the lpm. - */ - ccw_device_accumulate_irb(cdev, irb); - if (cdev->private->flags.dosense) { - if (ccw_device_do_sense(cdev, irb) == 0) { - cdev->private->state = DEV_STATE_W4SENSE; - } - return; - } - - /* Iff device is idle, reset timeout. */ - sch = to_subchannel(cdev->dev.parent); - if (!stsch(sch->schid, &sch->schib)) - if (sch->schib.scsw.actl == 0) - ccw_device_set_timeout(cdev, 0); - /* Call the handler. */ - ccw_device_call_handler(cdev); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); - queue_work(ccw_device_notify_work, &cdev->private->kick_work); - } else if (cdev->private->flags.doverify) - ccw_device_online_verify(cdev, 0); + ERR_PTR(-EIO)); } -static void -ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event) +void device_kill_io(struct subchannel *sch) { int ret; - struct subchannel *sch; + struct ccw_device *cdev; - sch = to_subchannel(cdev->dev.parent); - ccw_device_set_timeout(cdev, 0); + cdev = sch->dev.driver_data; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -1035,7 +994,7 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event) if (ret == -ENODEV) { if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else @@ -1044,12 +1003,12 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event) } if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-ETIMEDOUT)); + ERR_PTR(-EIO)); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); - } else if (cdev->private->flags.doverify) + } else /* Start delayed path verification. */ ccw_device_online_verify(cdev, 0); } @@ -1286,12 +1245,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME }, - [DEV_STATE_WAIT4IO] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout, - [DEV_EVENT_VERIFY] = ccw_device_delay_verify, - }, [DEV_STATE_QUIESCE] = { [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done, [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done, diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 1398367b5f6..a74785b9e4e 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -251,7 +251,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) */ CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel " "0.%x.%04x reports cmd reject\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); return -EOPNOTSUPP; } @@ -259,7 +259,8 @@ ccw_device_check_sense_id(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, " "lpum %02X, cnt %02d, sns :" " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - cdev->private->ssid, cdev->private->devno, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, irb->esw.esw0.sublog.lpum, irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], @@ -274,14 +275,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x " "on subchannel 0.%x.%04x is " "'not operational'\n", sch->orb.lpm, - cdev->private->devno, sch->schid.ssid, - sch->schid.sch_no); + cdev->private->dev_id.devno, + sch->schid.ssid, sch->schid.sch_no); return -EACCES; } /* Hmm, whatever happened, try again. */ CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " "subchannel 0.%x.%04x returns status %02X%02X\n", - cdev->private->devno, sch->schid.ssid, sch->schid.sch_no, + cdev->private->dev_id.devno, sch->schid.ssid, + sch->schid.sch_no, irb->scsw.dstat, irb->scsw.cstat); return -EAGAIN; } @@ -330,7 +332,7 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) /* fall through. */ default: /* Sense ID failed. Try asking VM. */ if (MACHINE_IS_VM) { - VM_virtual_device_info (cdev->private->devno, + VM_virtual_device_info (cdev->private->dev_id.devno, &cdev->private->senseid); if (cdev->private->senseid.cu_type != 0xFFFF) { /* Got the device information from VM. */ diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 84b9b18eabc..b39c1fa48ac 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -50,7 +50,6 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && - cdev->private->state != DEV_STATE_WAIT4IO && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; sch = to_subchannel(cdev->dev.parent); @@ -155,7 +154,6 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && - cdev->private->state != DEV_STATE_WAIT4IO && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; sch = to_subchannel(cdev->dev.parent); @@ -592,13 +590,13 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) int _ccw_device_get_subchannel_number(struct ccw_device *cdev) { - return cdev->private->sch_no; + return cdev->private->schid.sch_no; } int _ccw_device_get_device_number(struct ccw_device *cdev) { - return cdev->private->devno; + return cdev->private->dev_id.devno; } diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 84917b39de4..2975ce888c1 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -79,7 +79,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not " "operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, + sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); } @@ -135,7 +136,8 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, " "lpum %02X, cnt %02d, sns : " "%02X%02X%02X%02X %02X%02X%02X%02X ...\n", - cdev->private->ssid, cdev->private->devno, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, irb->esw.esw0.sublog.lpum, irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], @@ -147,7 +149,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, sch->orb.lpm); return -EACCES; } @@ -155,7 +157,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x " "is reserved by someone else\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); return -EUSERS; } @@ -261,7 +263,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) /* PGID command failed on this path. */ CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return ret; } @@ -301,7 +303,7 @@ static int __ccw_device_do_nop(struct ccw_device *cdev) /* nop command failed on this path. */ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return ret; } @@ -328,8 +330,9 @@ __ccw_device_check_pgid(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, " "cnt %02d, " "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - cdev->private->ssid, - cdev->private->devno, irb->esw.esw0.erw.scnt, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, + irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], irb->ecw[2], irb->ecw[3], irb->ecw[4], irb->ecw[5], @@ -339,7 +342,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return -EACCES; } @@ -362,7 +365,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return -EACCES; } diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index caf148d5caa..3f7cbce4cd8 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -32,19 +32,18 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) return; - CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " "received" " ... device %04x on subchannel 0.%x.%04x, dev_stat " ": %02X sch_stat : %02X\n", - cdev->private->devno, cdev->private->ssid, - cdev->private->sch_no, + cdev->private->dev_id.devno, cdev->private->schid.ssid, + cdev->private->schid.sch_no, irb->scsw.dstat, irb->scsw.cstat); if (irb->scsw.cc != 3) { char dbf_text[15]; - sprintf(dbf_text, "chk%x", cdev->private->sch_no); + sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, irb, sizeof (struct irb)); } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index cde822d8b5c..476aa1da5cb 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1741,7 +1741,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, void *ptr; int available; - sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no); + sprintf(dbf_text,"qfqs%4x",cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); for (i=0;i<no_input_qs;i++) { q=irq_ptr->input_qs[i]; @@ -2924,7 +2924,7 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) irq_ptr = cdev->private->qdio_data; - sprintf(dbf_text,"qehi%4x",cdev->private->sch_no); + sprintf(dbf_text,"qehi%4x",cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); @@ -2943,7 +2943,7 @@ qdio_initialize(struct qdio_initialize *init_data) int rc; char dbf_text[15]; - sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no); + sprintf(dbf_text,"qini%4x",init_data->cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); @@ -2964,7 +2964,7 @@ qdio_allocate(struct qdio_initialize *init_data) struct qdio_irq *irq_ptr; char dbf_text[15]; - sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no); + sprintf(dbf_text,"qalc%4x",init_data->cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) || @@ -3187,7 +3187,7 @@ qdio_establish(struct qdio_initialize *init_data) tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET); } - sprintf(dbf_text,"qest%4x",cdev->private->sch_no); + sprintf(dbf_text,"qest%4x",cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); @@ -3529,7 +3529,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags, #ifdef CONFIG_QDIO_DEBUG char dbf_text[20]; - sprintf(dbf_text,"doQD%04x",cdev->private->sch_no); + sprintf(dbf_text,"doQD%04x",cdev->private->schid.sch_no); QDIO_DBF_TEXT3(0,trace,dbf_text); #endif /* CONFIG_QDIO_DEBUG */ diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index c5ccd20b110..79d89c36891 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -739,11 +739,16 @@ static void ap_scan_bus(void *data) dev = bus_find_device(&ap_bus_type, NULL, (void *)(unsigned long)qid, __ap_scan_bus); + rc = ap_query_queue(qid, &queue_depth, &device_type); + if (dev && rc) { + put_device(dev); + device_unregister(dev); + continue; + } if (dev) { put_device(dev); continue; } - rc = ap_query_queue(qid, &queue_depth, &device_type); if (rc) continue; rc = ap_init_queue(qid); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 8f882690994..74c0eac083e 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -107,6 +107,10 @@ zfcp_address_to_sg(void *address, struct scatterlist *list) (ZFCP_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ +#define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) + /* max. number of (data buffer) SBALEs in largest SBAL chain + multiplied with number of sectors per 4k block */ + /* FIXME(tune): free space should be one max. SBAL chain plus what? */ #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ - (ZFCP_MAX_SBALS_PER_REQ + 4)) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 4d2bc798132..452d96f92a1 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -58,6 +58,7 @@ struct zfcp_data zfcp_data = { .cmd_per_lun = 1, .use_clustering = 1, .sdev_attrs = zfcp_sysfs_sdev_attrs, + .max_sectors = ZFCP_MAX_SECTORS, }, .driver_version = ZFCP_VERSION, }; diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index d27e4f6d704..a54e4140683 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -4,11 +4,9 @@ * Copyright (C) 2001 David S. Miller (davem@redhat.com) */ -#include <linux/kernel.h> #include <linux/kthread.h> -#include <linux/sched.h> -#include <linux/slab.h> #include <linux/delay.h> +#include <linux/kmod.h> #include <asm/oplib.h> #include <asm/ebus.h> @@ -197,7 +195,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); shutting_down = 1; - if (kernel_execve("/sbin/shutdown", argv, envp) < 0) + if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0) printk(KERN_CRIT "envctrl: shutdown execution failed\n"); } diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 728a133d0fc..fff4660cdf9 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -20,16 +20,12 @@ */ #include <linux/module.h> -#include <linux/sched.h> +#include <linux/init.h> #include <linux/kthread.h> -#include <linux/errno.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/init.h> #include <linux/miscdevice.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/kernel.h> +#include <linux/kmod.h> #include <asm/ebus.h> #include <asm/uaccess.h> @@ -980,7 +976,7 @@ static void envctrl_do_shutdown(void) inprog = 1; printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); - ret = kernel_execve("/sbin/shutdown", argv, envp); + ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0); if (ret < 0) { printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); inprog = 0; /* unlikely to succeed, but we could try again */ diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 935952ef88f..98fcbb3d556 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -61,11 +61,11 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde else sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; sdev->ofdev.dev.bus = &sbus_bus_type; - strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name); + sprintf(sdev->ofdev.dev.bus_id, "sbus[%08x]", dp->node); if (of_device_register(&sdev->ofdev) != 0) printk(KERN_DEBUG "sbus: device registration error for %s!\n", - sdev->ofdev.dev.bus_id); + dp->path_component_name); } static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 5f8c26cd66c..b091a0fc4eb 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -66,6 +66,9 @@ 2.26.02.006 - Fix 9550SX pchip reset timeout. Add big endian support. 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic(). + 2.26.02.008 - Free irq handler in __twa_shutdown(). + Serialize reset code. + Add support for 9650SE controllers. */ #include <linux/module.h> @@ -89,7 +92,7 @@ #include "3w-9xxx.h" /* Globals */ -#define TW_DRIVER_VERSION "2.26.02.007" +#define TW_DRIVER_VERSION "2.26.02.008" static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; static unsigned int twa_device_extension_count; static int twa_major = -1; @@ -566,9 +569,9 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) goto out; } - tw_dev->working_srl = fw_on_ctlr_srl; - tw_dev->working_branch = fw_on_ctlr_branch; - tw_dev->working_build = fw_on_ctlr_build; + tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl; + tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch; + tw_dev->tw_compat_info.working_build = fw_on_ctlr_build; /* Try base mode compatibility */ if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { @@ -590,10 +593,23 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) } goto out; } - tw_dev->working_srl = TW_BASE_FW_SRL; - tw_dev->working_branch = TW_BASE_FW_BRANCH; - tw_dev->working_build = TW_BASE_FW_BUILD; - } + tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL; + tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH; + tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD; + } + + /* Load rest of compatibility struct */ + strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); + tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; + tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; + tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; + tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL; + tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH; + tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD; + tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl; + tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch; + tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build; + retval = 0; out: return retval; @@ -631,7 +647,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int goto out2; /* Check data buffer size */ - if (driver_command.buffer_length > TW_MAX_SECTORS * 512) { + if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) { retval = TW_IOCTL_ERROR_OS_EINVAL; goto out2; } @@ -680,13 +696,6 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int /* Now wait for command to complete */ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); - /* See if we reset while waiting for the ioctl to complete */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) { - clear_bit(TW_IN_RESET, &tw_dev->flags); - retval = TW_IOCTL_ERROR_OS_ERESTARTSYS; - goto out3; - } - /* We timed out, and didn't get an interrupt */ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { /* Now we need to reset the board */ @@ -694,11 +703,6 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int tw_dev->host->host_no, TW_DRIVER, 0xc, cmd); retval = TW_IOCTL_ERROR_OS_EIO; - spin_lock_irqsave(tw_dev->host->host_lock, flags); - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - tw_dev->posted_request_count--; - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); twa_reset_device_extension(tw_dev, 1); goto out3; } @@ -717,16 +721,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int tw_ioctl->driver_command.status = 0; /* Copy compatiblity struct into ioctl data buffer */ tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer; - strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); - tw_compat_info->working_srl = tw_dev->working_srl; - tw_compat_info->working_branch = tw_dev->working_branch; - tw_compat_info->working_build = tw_dev->working_build; - tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL; - tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH; - tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD; - tw_compat_info->driver_srl_low = TW_BASE_FW_SRL; - tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH; - tw_compat_info->driver_build_low = TW_BASE_FW_BUILD; + memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info)); break; case TW_IOCTL_GET_LAST_EVENT: if (tw_dev->event_queue_wrapped) { @@ -895,7 +890,8 @@ static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) } if (status_reg_value & TW_STATUS_QUEUE_ERROR) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); + if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags))) + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); } @@ -939,10 +935,12 @@ static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev) unsigned long before; int retval = 1; - if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) { + if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) || + (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) { before = jiffies; while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) { response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev)); + msleep(1); if (time_after(jiffies, before + HZ * 30)) goto out; } @@ -1214,6 +1212,10 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) handled = 1; + /* If we are resetting, bail */ + if (test_bit(TW_IN_RESET, &tw_dev->flags)) + goto twa_interrupt_bail; + /* Check controller for errors */ if (twa_check_bits(status_reg_value)) { if (twa_decode_bits(tw_dev, status_reg_value)) { @@ -1355,8 +1357,8 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { newcommand = &full_command_packet->command.newcommand; - newcommand->request_id__lunl = - TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id); + newcommand->request_id__lunl = + cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); newcommand->sg_list[0].length = cpu_to_le32(length); newcommand->sgl_entries__lunh = @@ -1531,6 +1533,13 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, int retval = 1; command_que_value = tw_dev->command_packet_phys[request_id]; + + /* For 9650SE write low 4 bytes first */ + if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) { + command_que_value += TW_COMMAND_OFFSET; + writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev)); + } + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); if (twa_check_bits(status_reg_value)) @@ -1557,13 +1566,17 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, TW_UNMASK_COMMAND_INTERRUPT(tw_dev); goto out; } else { - /* We successfully posted the command packet */ - if (sizeof(dma_addr_t) > 4) { - command_que_value += TW_COMMAND_OFFSET; - writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4); + if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) { + /* Now write upper 4 bytes */ + writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4); } else { - writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); + if (sizeof(dma_addr_t) > 4) { + command_que_value += TW_COMMAND_OFFSET; + writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); + writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4); + } else { + writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); + } } tw_dev->state[request_id] = TW_S_POSTED; tw_dev->posted_request_count++; @@ -1620,14 +1633,9 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res goto out; TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); + clear_bit(TW_IN_RESET, &tw_dev->flags); + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - /* Wake up any ioctl that was pending before the reset */ - if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) { - clear_bit(TW_IN_RESET, &tw_dev->flags); - } else { - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - wake_up(&tw_dev->ioctl_wqueue); - } retval = 0; out: return retval; @@ -1736,6 +1744,9 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt) "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n", TW_DRIVER, 0x2c, SCpnt->cmnd[0]); + /* Make sure we are not issuing an ioctl or resetting from ioctl */ + mutex_lock(&tw_dev->ioctl_lock); + /* Now reset the card and some of the device extension data */ if (twa_reset_device_extension(tw_dev, 0)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); @@ -1744,6 +1755,7 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt) retval = SUCCESS; out: + mutex_unlock(&tw_dev->ioctl_lock); return retval; } /* End twa_scsi_eh_reset() */ @@ -1753,8 +1765,14 @@ static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd int request_id, retval; TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + /* If we are resetting due to timed out ioctl, report as busy */ + if (test_bit(TW_IN_RESET, &tw_dev->flags)) { + retval = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + /* Check if this FW supports luns */ - if ((SCpnt->device->lun != 0) && (tw_dev->working_srl < TW_FW_SRL_LUNS_SUPPORTED)) { + if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) { SCpnt->result = (DID_BAD_TARGET << 16); done(SCpnt); retval = 0; @@ -1960,6 +1978,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev) /* Disable interrupts */ TW_DISABLE_INTERRUPTS(tw_dev); + /* Free up the IRQ */ + free_irq(tw_dev->tw_pci_dev->irq, tw_dev); + printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no); /* Tell the card we are shutting down */ @@ -2091,21 +2112,25 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id /* Initialize the card */ if (twa_reset_sequence(tw_dev, 0)) - goto out_release_mem_region; + goto out_iounmap; /* Set host specific parameters */ - host->max_id = TW_MAX_UNITS; + if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE) + host->max_id = TW_MAX_UNITS_9650SE; + else + host->max_id = TW_MAX_UNITS; + host->max_cmd_len = TW_MAX_CDB_LEN; /* Channels aren't supported by adapter */ - host->max_lun = TW_MAX_LUNS(tw_dev->working_srl); + host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl); host->max_channel = 0; /* Register the card with the kernel SCSI layer */ retval = scsi_add_host(host, &pdev->dev); if (retval) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed"); - goto out_release_mem_region; + goto out_iounmap; } pci_set_drvdata(pdev, host); @@ -2145,6 +2170,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id out_remove_host: scsi_remove_host(host); +out_iounmap: + iounmap(tw_dev->base_addr); out_release_mem_region: pci_release_regions(pdev); out_free_device_extension: @@ -2170,12 +2197,12 @@ static void twa_remove(struct pci_dev *pdev) twa_major = -1; } - /* Free up the IRQ */ - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - /* Shutdown the card */ __twa_shutdown(tw_dev); + /* Free IO remapping */ + iounmap(tw_dev->base_addr); + /* Free up the mem region */ pci_release_regions(pdev); @@ -2193,6 +2220,8 @@ static struct pci_device_id twa_pci_tbl[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { } }; MODULE_DEVICE_TABLE(pci, twa_pci_tbl); diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index e5685be96f4..7901517d451 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h @@ -289,7 +289,6 @@ static twa_message_type twa_error_table[] = { #define TW_STATUS_VALID_INTERRUPT 0x00DF0000 /* PCI related defines */ -#define TW_NUMDEVICES 1 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 #define TW_PCI_CLEAR_PCI_ABORT 0x2000 @@ -335,6 +334,7 @@ static twa_message_type twa_error_table[] = { #define TW_ALIGNMENT_9000 4 /* 4 bytes */ #define TW_ALIGNMENT_9000_SGL 0x3 #define TW_MAX_UNITS 16 +#define TW_MAX_UNITS_9650SE 32 #define TW_INIT_MESSAGE_CREDITS 0x100 #define TW_INIT_COMMAND_PACKET_SIZE 0x3 #define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 @@ -354,7 +354,6 @@ static twa_message_type twa_error_table[] = { #define TW_MAX_RESPONSE_DRAIN 256 #define TW_MAX_AEN_DRAIN 40 #define TW_IN_RESET 2 -#define TW_IN_CHRDEV_IOCTL 3 #define TW_IN_ATTENTION_LOOP 4 #define TW_MAX_SECTORS 256 #define TW_AEN_WAIT_TIME 1000 @@ -417,6 +416,9 @@ static twa_message_type twa_error_table[] = { #ifndef PCI_DEVICE_ID_3WARE_9550SX #define PCI_DEVICE_ID_3WARE_9550SX 0x1003 #endif +#ifndef PCI_DEVICE_ID_3WARE_9650SE +#define PCI_DEVICE_ID_3WARE_9650SE 0x1004 +#endif /* Bitmask macros to eliminate bitfields */ @@ -442,6 +444,7 @@ static twa_message_type twa_error_table[] = { #define TW_CONTROL_REG_ADDR(x) (x->base_addr) #define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4) #define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8)) +#define TW_COMMAND_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x20) #define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC) #define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x30) #define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x))) @@ -626,6 +629,9 @@ typedef struct TAG_TW_Compatibility_Info unsigned short driver_srl_low; unsigned short driver_branch_low; unsigned short driver_build_low; + unsigned short fw_on_ctlr_srl; + unsigned short fw_on_ctlr_branch; + unsigned short fw_on_ctlr_build; } TW_Compatibility_Info; #pragma pack() @@ -668,9 +674,7 @@ typedef struct TAG_TW_Device_Extension { wait_queue_head_t ioctl_wqueue; struct mutex ioctl_lock; char aen_clobber; - unsigned short working_srl; - unsigned short working_branch; - unsigned short working_build; + TW_Compatibility_Info tw_compat_info; } TW_Device_Extension; #endif /* _3W_9XXX_H */ diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 689dc4cc789..3075204915c 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3600,5 +3600,16 @@ static void __exit BusLogic_exit(void) __setup("BusLogic=", BusLogic_Setup); +static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl); + module_init(BusLogic_init); module_exit(BusLogic_exit); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index a0d1cee0be7..306f46b85a5 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -238,7 +238,7 @@ #include <linux/module.h> #include <linux/sched.h> #include <asm/irq.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/blkdev.h> #include <asm/system.h> #include <linux/errno.h> diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index df3346b5caf..170a4344cbb 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -53,14 +53,6 @@ struct ahd_platform_data; struct scb_platform_data; /****************************** Useful Macros *********************************/ -#ifndef MAX -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - #ifndef TRUE #define TRUE 1 #endif @@ -972,8 +964,6 @@ int ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, int ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, u_int start_addr, u_int count); -int ahd_wait_seeprom(struct ahd_softc *ahd); -int ahd_verify_vpd_cksum(struct vpd_config *vpd); int ahd_verify_cksum(struct seeprom_config *sc); int ahd_acquire_seeprom(struct ahd_softc *ahd); void ahd_release_seeprom(struct ahd_softc *ahd); @@ -1320,8 +1310,6 @@ struct ahd_pci_identity { char *name; ahd_device_setup_t *setup; }; -extern struct ahd_pci_identity ahd_pci_ident_table []; -extern const u_int ahd_num_pci_devs; /***************************** VL/EISA Declarations ***************************/ struct aic7770_identity { @@ -1339,15 +1327,6 @@ extern const int ahd_num_aic7770_devs; /*************************** Function Declarations ****************************/ /******************************************************************************/ void ahd_reset_cmds_pending(struct ahd_softc *ahd); -u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl); -void ahd_busy_tcl(struct ahd_softc *ahd, - u_int tcl, u_int busyid); -static __inline void ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl); -static __inline void -ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) -{ - ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL); -} /***************************** PCI Front End *********************************/ struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); @@ -1356,7 +1335,6 @@ int ahd_pci_config(struct ahd_softc *, int ahd_pci_test_register_access(struct ahd_softc *); /************************** SCB and SCB queue management **********************/ -int ahd_probe_scbs(struct ahd_softc *); void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb); int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, @@ -1374,33 +1352,20 @@ int ahd_parse_vpddata(struct ahd_softc *ahd, int ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc); void ahd_intr_enable(struct ahd_softc *ahd, int enable); -void ahd_update_coalescing_values(struct ahd_softc *ahd, - u_int timer, - u_int maxcmds, - u_int mincmds); -void ahd_enable_coalescing(struct ahd_softc *ahd, - int enable); void ahd_pause_and_flushwork(struct ahd_softc *ahd); int ahd_suspend(struct ahd_softc *ahd); -int ahd_resume(struct ahd_softc *ahd); void ahd_set_unit(struct ahd_softc *, int); void ahd_set_name(struct ahd_softc *, char *); struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb); -void ahd_alloc_scbs(struct ahd_softc *ahd); void ahd_free(struct ahd_softc *ahd); int ahd_reset(struct ahd_softc *ahd, int reinit); -void ahd_shutdown(void *arg); int ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value); int ahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value); -int ahd_wait_flexport(struct ahd_softc *ahd); /*************************** Interrupt Services *******************************/ -void ahd_pci_intr(struct ahd_softc *ahd); -void ahd_clear_intstat(struct ahd_softc *ahd); -void ahd_flush_qoutfifo(struct ahd_softc *ahd); void ahd_run_qoutfifo(struct ahd_softc *ahd); #ifdef AHD_TARGET_MODE void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused); @@ -1409,7 +1374,6 @@ void ahd_handle_hwerrint(struct ahd_softc *ahd); void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat); void ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat); -void ahd_clear_critical_section(struct ahd_softc *ahd); /***************************** Error Recovery *********************************/ typedef enum { @@ -1426,23 +1390,9 @@ int ahd_search_disc_list(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, int stop_on_first, int remove, int save_state); -void ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb); int ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset); -int ahd_abort_scbs(struct ahd_softc *ahd, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status); -void ahd_restart(struct ahd_softc *ahd); -void ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo); -void ahd_handle_scb_status(struct ahd_softc *ahd, - struct scb *scb); -void ahd_handle_scsi_status(struct ahd_softc *ahd, - struct scb *scb); -void ahd_calc_residual(struct ahd_softc *ahd, - struct scb *scb); /*************************** Utility Functions ********************************/ -struct ahd_phase_table_entry* - ahd_lookup_phase_entry(int phase); void ahd_compile_devinfo(struct ahd_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, @@ -1450,14 +1400,6 @@ void ahd_compile_devinfo(struct ahd_devinfo *devinfo, /************************** Transfer Negotiation ******************************/ void ahd_find_syncrate(struct ahd_softc *ahd, u_int *period, u_int *ppr_options, u_int maxsync); -void ahd_validate_offset(struct ahd_softc *ahd, - struct ahd_initiator_tinfo *tinfo, - u_int period, u_int *offset, - int wide, role_t role); -void ahd_validate_width(struct ahd_softc *ahd, - struct ahd_initiator_tinfo *tinfo, - u_int *bus_width, - role_t role); /* * Negotiation types. These are used to qualify if we should renegotiate * even if our goal and current transport parameters are identical. @@ -1486,11 +1428,6 @@ typedef enum { AHD_QUEUE_TAGGED } ahd_queue_alg; -void ahd_set_tags(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - ahd_queue_alg alg); - /**************************** Target Mode *************************************/ #ifdef AHD_TARGET_MODE void ahd_send_lstate_events(struct ahd_softc *, @@ -1528,10 +1465,8 @@ extern uint32_t ahd_debug; #define AHD_SHOW_INT_COALESCING 0x10000 #define AHD_DEBUG_SEQUENCER 0x20000 #endif -void ahd_print_scb(struct scb *scb); void ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); -void ahd_dump_sglist(struct scb *scb); void ahd_dump_card_state(struct ahd_softc *ahd); int ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, @@ -1540,5 +1475,4 @@ int ahd_print_register(ahd_reg_parse_entry_t *table, u_int value, u_int *cur_column, u_int wrap_point); -void ahd_dump_scbs(struct ahd_softc *ahd); #endif /* _AIC79XX_H_ */ diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 653818d2f80..07a86a30f67 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -52,7 +52,7 @@ /***************************** Lookup Tables **********************************/ -char *ahd_chip_names[] = +static char *ahd_chip_names[] = { "NONE", "aic7901", @@ -237,10 +237,33 @@ static int ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd); #endif +static int ahd_abort_scbs(struct ahd_softc *ahd, int target, + char channel, int lun, u_int tag, + role_t role, uint32_t status); +static void ahd_alloc_scbs(struct ahd_softc *ahd); +static void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, + u_int scbid); +static void ahd_calc_residual(struct ahd_softc *ahd, + struct scb *scb); +static void ahd_clear_critical_section(struct ahd_softc *ahd); +static void ahd_clear_intstat(struct ahd_softc *ahd); +static void ahd_enable_coalescing(struct ahd_softc *ahd, + int enable); +static u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl); +static void ahd_freeze_devq(struct ahd_softc *ahd, + struct scb *scb); +static void ahd_handle_scb_status(struct ahd_softc *ahd, + struct scb *scb); +static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase); +static void ahd_shutdown(void *arg); +static void ahd_update_coalescing_values(struct ahd_softc *ahd, + u_int timer, + u_int maxcmds, + u_int mincmds); +static int ahd_verify_vpd_cksum(struct vpd_config *vpd); +static int ahd_wait_seeprom(struct ahd_softc *ahd); + /******************************** Private Inlines *****************************/ -static __inline void ahd_assert_atn(struct ahd_softc *ahd); -static __inline int ahd_currently_packetized(struct ahd_softc *ahd); -static __inline int ahd_set_active_fifo(struct ahd_softc *ahd); static __inline void ahd_assert_atn(struct ahd_softc *ahd) @@ -294,11 +317,44 @@ ahd_set_active_fifo(struct ahd_softc *ahd) } } +static __inline void +ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) +{ + ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL); +} + +/* + * Determine whether the sequencer reported a residual + * for this SCB/transaction. + */ +static __inline void +ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) +{ + uint32_t sgptr; + + sgptr = ahd_le32toh(scb->hscb->sgptr); + if ((sgptr & SG_STATUS_VALID) != 0) + ahd_calc_residual(ahd, scb); +} + +static __inline void +ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) +{ + uint32_t sgptr; + + sgptr = ahd_le32toh(scb->hscb->sgptr); + if ((sgptr & SG_STATUS_VALID) != 0) + ahd_handle_scb_status(ahd, scb); + else + ahd_done(ahd, scb); +} + + /************************* Sequencer Execution Control ************************/ /* * Restart the sequencer program from address zero */ -void +static void ahd_restart(struct ahd_softc *ahd) { @@ -342,7 +398,7 @@ ahd_restart(struct ahd_softc *ahd) ahd_unpause(ahd); } -void +static void ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo) { ahd_mode_state saved_modes; @@ -366,7 +422,7 @@ ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo) * Flush and completed commands that are sitting in the command * complete queues down on the chip but have yet to be dma'ed back up. */ -void +static void ahd_flush_qoutfifo(struct ahd_softc *ahd) { struct scb *scb; @@ -905,6 +961,51 @@ ahd_handle_hwerrint(struct ahd_softc *ahd) ahd_free(ahd); } +#ifdef AHD_DEBUG +static void +ahd_dump_sglist(struct scb *scb) +{ + int i; + + if (scb->sg_count > 0) { + if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) { + struct ahd_dma64_seg *sg_list; + + sg_list = (struct ahd_dma64_seg*)scb->sg_list; + for (i = 0; i < scb->sg_count; i++) { + uint64_t addr; + uint32_t len; + + addr = ahd_le64toh(sg_list[i].addr); + len = ahd_le32toh(sg_list[i].len); + printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", + i, + (uint32_t)((addr >> 32) & 0xFFFFFFFF), + (uint32_t)(addr & 0xFFFFFFFF), + sg_list[i].len & AHD_SG_LEN_MASK, + (sg_list[i].len & AHD_DMA_LAST_SEG) + ? " Last" : ""); + } + } else { + struct ahd_dma_seg *sg_list; + + sg_list = (struct ahd_dma_seg*)scb->sg_list; + for (i = 0; i < scb->sg_count; i++) { + uint32_t len; + + len = ahd_le32toh(sg_list[i].len); + printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", + i, + (len & AHD_SG_HIGH_ADDR_MASK) >> 24, + ahd_le32toh(sg_list[i].addr), + len & AHD_SG_LEN_MASK, + len & AHD_DMA_LAST_SEG ? " Last" : ""); + } + } + } +} +#endif /* AHD_DEBUG */ + void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) { @@ -1053,10 +1154,12 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) * If a target takes us into the command phase * assume that it has been externally reset and * has thus lost our previous packetized negotiation - * agreement. - * Revert to async/narrow transfers until we - * can renegotiate with the device and notify - * the OSM about the reset. + * agreement. Since we have not sent an identify + * message and may not have fully qualified the + * connection, we change our command to TUR, assert + * ATN and ABORT the task when we go to message in + * phase. The OSM will see the REQUEUE_REQUEST + * status and retry the command. */ scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); @@ -1083,7 +1186,28 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, AHD_TRANS_ACTIVE, /*paused*/TRUE); - scb->flags |= SCB_EXTERNAL_RESET; + /* Hand-craft TUR command */ + ahd_outb(ahd, SCB_CDB_STORE, 0); + ahd_outb(ahd, SCB_CDB_STORE+1, 0); + ahd_outb(ahd, SCB_CDB_STORE+2, 0); + ahd_outb(ahd, SCB_CDB_STORE+3, 0); + ahd_outb(ahd, SCB_CDB_STORE+4, 0); + ahd_outb(ahd, SCB_CDB_STORE+5, 0); + ahd_outb(ahd, SCB_CDB_LEN, 6); + scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE); + scb->hscb->control |= MK_MESSAGE; + ahd_outb(ahd, SCB_CONTROL, scb->hscb->control); + ahd_outb(ahd, MSG_OUT, HOST_MSG); + ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); + /* + * The lun is 0, regardless of the SCB's lun + * as we have not sent an identify message. + */ + ahd_outb(ahd, SAVED_LUN, 0); + ahd_outb(ahd, SEQ_FLAGS, 0); + ahd_assert_atn(ahd); + scb->flags &= ~SCB_PACKETIZED; + scb->flags |= SCB_ABORT|SCB_EXTERNAL_RESET; ahd_freeze_devq(ahd, scb); ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_freeze_scb(scb); @@ -1519,8 +1643,10 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) /* * Ignore external resets after a bus reset. */ - if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) + if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) { + ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); return; + } /* * Clear bus reset flag @@ -2200,6 +2326,22 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) if (sent_msg == MSG_ABORT_TAG) tag = SCB_GET_TAG(scb); + if ((scb->flags & SCB_EXTERNAL_RESET) != 0) { + /* + * This abort is in response to an + * unexpected switch to command phase + * for a packetized connection. Since + * the identify message was never sent, + * "saved lun" is 0. We really want to + * abort only the SCB that encountered + * this error, which could have a different + * lun. The SCB will be retried so the OS + * will see the UA after renegotiating to + * packetized. + */ + tag = SCB_GET_TAG(scb); + saved_lun = scb->hscb->lun; + } found = ahd_abort_scbs(ahd, target, 'A', saved_lun, tag, ROLE_INITIATOR, CAM_REQ_ABORTED); @@ -2523,7 +2665,7 @@ ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) } #define AHD_MAX_STEPS 2000 -void +static void ahd_clear_critical_section(struct ahd_softc *ahd) { ahd_mode_state saved_modes; @@ -2646,7 +2788,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd) /* * Clear any pending interrupt status. */ -void +static void ahd_clear_intstat(struct ahd_softc *ahd) { AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), @@ -2677,6 +2819,8 @@ ahd_clear_intstat(struct ahd_softc *ahd) #ifdef AHD_DEBUG uint32_t ahd_debug = AHD_DEBUG_OPTS; #endif + +#if 0 void ahd_print_scb(struct scb *scb) { @@ -2701,49 +2845,7 @@ ahd_print_scb(struct scb *scb) SCB_GET_TAG(scb)); ahd_dump_sglist(scb); } - -void -ahd_dump_sglist(struct scb *scb) -{ - int i; - - if (scb->sg_count > 0) { - if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg_list; - - sg_list = (struct ahd_dma64_seg*)scb->sg_list; - for (i = 0; i < scb->sg_count; i++) { - uint64_t addr; - uint32_t len; - - addr = ahd_le64toh(sg_list[i].addr); - len = ahd_le32toh(sg_list[i].len); - printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", - i, - (uint32_t)((addr >> 32) & 0xFFFFFFFF), - (uint32_t)(addr & 0xFFFFFFFF), - sg_list[i].len & AHD_SG_LEN_MASK, - (sg_list[i].len & AHD_DMA_LAST_SEG) - ? " Last" : ""); - } - } else { - struct ahd_dma_seg *sg_list; - - sg_list = (struct ahd_dma_seg*)scb->sg_list; - for (i = 0; i < scb->sg_count; i++) { - uint32_t len; - - len = ahd_le32toh(sg_list[i].len); - printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", - i, - (len & AHD_SG_HIGH_ADDR_MASK) >> 24, - ahd_le32toh(sg_list[i].addr), - len & AHD_SG_LEN_MASK, - len & AHD_DMA_LAST_SEG ? " Last" : ""); - } - } - } -} +#endif /* 0 */ /************************* Transfer Negotiation *******************************/ /* @@ -2850,14 +2952,14 @@ ahd_devlimited_syncrate(struct ahd_softc *ahd, transinfo = &tinfo->goal; *ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN); if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) { - maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2); + maxsync = max(maxsync, (u_int)AHD_SYNCRATE_ULTRA2); *ppr_options &= ~MSG_EXT_PPR_DT_REQ; } if (transinfo->period == 0) { *period = 0; *ppr_options = 0; } else { - *period = MAX(*period, transinfo->period); + *period = max(*period, (u_int)transinfo->period); ahd_find_syncrate(ahd, period, ppr_options, maxsync); } } @@ -2906,7 +3008,7 @@ ahd_find_syncrate(struct ahd_softc *ahd, u_int *period, * Truncate the given synchronous offset to a value the * current adapter type and syncrate are capable of. */ -void +static void ahd_validate_offset(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, u_int period, u_int *offset, int wide, @@ -2924,12 +3026,12 @@ ahd_validate_offset(struct ahd_softc *ahd, maxoffset = MAX_OFFSET_PACED; } else maxoffset = MAX_OFFSET_NON_PACED; - *offset = MIN(*offset, maxoffset); + *offset = min(*offset, maxoffset); if (tinfo != NULL) { if (role == ROLE_TARGET) - *offset = MIN(*offset, tinfo->user.offset); + *offset = min(*offset, (u_int)tinfo->user.offset); else - *offset = MIN(*offset, tinfo->goal.offset); + *offset = min(*offset, (u_int)tinfo->goal.offset); } } @@ -2937,7 +3039,7 @@ ahd_validate_offset(struct ahd_softc *ahd, * Truncate the given transfer width parameter to a value the * current adapter type is capable of. */ -void +static void ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, u_int *bus_width, role_t role) { @@ -2955,9 +3057,9 @@ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, } if (tinfo != NULL) { if (role == ROLE_TARGET) - *bus_width = MIN(tinfo->user.width, *bus_width); + *bus_width = min((u_int)tinfo->user.width, *bus_width); else - *bus_width = MIN(tinfo->goal.width, *bus_width); + *bus_width = min((u_int)tinfo->goal.width, *bus_width); } } @@ -3210,7 +3312,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, /* * Update the current state of tagged queuing for a given target. */ -void +static void ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, ahd_queue_alg alg) { @@ -3466,7 +3568,7 @@ ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) devinfo->target, devinfo->lun); } -struct ahd_phase_table_entry* +static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase) { struct ahd_phase_table_entry *entry; @@ -5351,7 +5453,7 @@ ahd_free(struct ahd_softc *ahd) return; } -void +static void ahd_shutdown(void *arg) { struct ahd_softc *ahd; @@ -5480,7 +5582,7 @@ ahd_reset(struct ahd_softc *ahd, int reinit) /* * Determine the number of SCBs available on the controller */ -int +static int ahd_probe_scbs(struct ahd_softc *ahd) { int i; @@ -5929,7 +6031,7 @@ ahd_free_scb(struct ahd_softc *ahd, struct scb *scb) ahd_platform_scb_free(ahd, scb); } -void +static void ahd_alloc_scbs(struct ahd_softc *ahd) { struct scb_data *scb_data; @@ -6057,9 +6159,9 @@ ahd_alloc_scbs(struct ahd_softc *ahd) #endif } - newcount = MIN(scb_data->sense_left, scb_data->scbs_left); - newcount = MIN(newcount, scb_data->sgs_left); - newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs)); + newcount = min(scb_data->sense_left, scb_data->scbs_left); + newcount = min(newcount, scb_data->sgs_left); + newcount = min(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs)); for (i = 0; i < newcount; i++) { struct scb_platform_data *pdata; u_int col_tag; @@ -6982,7 +7084,7 @@ ahd_intr_enable(struct ahd_softc *ahd, int enable) ahd_outb(ahd, HCNTRL, hcntrl); } -void +static void ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, u_int mincmds) { @@ -7000,7 +7102,7 @@ ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds); } -void +static void ahd_enable_coalescing(struct ahd_softc *ahd, int enable) { @@ -7070,6 +7172,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd->flags &= ~AHD_ALL_INTERRUPTS; } +#if 0 int ahd_suspend(struct ahd_softc *ahd) { @@ -7083,7 +7186,9 @@ ahd_suspend(struct ahd_softc *ahd) ahd_shutdown(ahd); return (0); } +#endif /* 0 */ +#if 0 int ahd_resume(struct ahd_softc *ahd) { @@ -7093,6 +7198,7 @@ ahd_resume(struct ahd_softc *ahd) ahd_restart(ahd); return (0); } +#endif /* 0 */ /************************** Busy Target Table *********************************/ /* @@ -7125,7 +7231,7 @@ ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) /* * Return the untagged transaction id for a given target/channel lun. */ -u_int +static u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl) { u_int scbid; @@ -7138,7 +7244,7 @@ ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl) return (scbid); } -void +static void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid) { u_int scb_offset; @@ -7186,7 +7292,7 @@ ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target, return match; } -void +static void ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb) { int target; @@ -7690,7 +7796,7 @@ ahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid) * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer * is paused before it is called. */ -int +static int ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status) { @@ -7920,6 +8026,11 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) ahd_clear_fifo(ahd, 1); /* + * Clear SCSI interrupt status + */ + ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); + + /* * Reenable selections */ ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); @@ -7952,10 +8063,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) } } #endif - /* Notify the XPT that a bus reset occurred */ - ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); - /* * Revert to async/narrow transfers until we renegotiate. */ @@ -7977,6 +8084,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) } } + /* Notify the XPT that a bus reset occurred */ + ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD, AC_BUS_RESET); + ahd_restart(ahd); return (found); @@ -8019,18 +8130,8 @@ ahd_stat_timer(void *arg) } /****************************** Status Processing *****************************/ -void -ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb) -{ - if (scb->hscb->shared_data.istatus.scsi_status != 0) { - ahd_handle_scsi_status(ahd, scb); - } else { - ahd_calc_residual(ahd, scb); - ahd_done(ahd, scb); - } -} -void +static void ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) { struct hardware_scb *hscb; @@ -8238,10 +8339,21 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) } } +static void +ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb) +{ + if (scb->hscb->shared_data.istatus.scsi_status != 0) { + ahd_handle_scsi_status(ahd, scb); + } else { + ahd_calc_residual(ahd, scb); + ahd_done(ahd, scb); + } +} + /* * Calculate the residual for a just completed SCB. */ -void +static void ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) { struct hardware_scb *hscb; @@ -8668,7 +8780,7 @@ ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address) if (skip_addr > i) { int end_addr; - end_addr = MIN(address, skip_addr); + end_addr = min(address, skip_addr); address_offset += end_addr - i; i = skip_addr; } else { @@ -9092,6 +9204,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_unpause(ahd); } +#if 0 void ahd_dump_scbs(struct ahd_softc *ahd) { @@ -9117,6 +9230,7 @@ ahd_dump_scbs(struct ahd_softc *ahd) ahd_set_scbptr(ahd, saved_scb_index); ahd_restore_modes(ahd, saved_modes); } +#endif /* 0 */ /**************************** Flexport Logic **********************************/ /* @@ -9219,7 +9333,7 @@ ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, /* * Wait ~100us for the serial eeprom to satisfy our request. */ -int +static int ahd_wait_seeprom(struct ahd_softc *ahd) { int cnt; @@ -9237,7 +9351,7 @@ ahd_wait_seeprom(struct ahd_softc *ahd) * Validate the two checksums in the per_channel * vital product data struct. */ -int +static int ahd_verify_vpd_cksum(struct vpd_config *vpd) { int i; @@ -9316,6 +9430,24 @@ ahd_release_seeprom(struct ahd_softc *ahd) /* Currently a no-op */ } +/* + * Wait at most 2 seconds for flexport arbitration to succeed. + */ +static int +ahd_wait_flexport(struct ahd_softc *ahd) +{ + int cnt; + + AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); + cnt = 1000000 * 2 / 5; + while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt) + ahd_delay(5); + + if (cnt == 0) + return (ETIMEDOUT); + return (0); +} + int ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value) { @@ -9357,24 +9489,6 @@ ahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value) return (0); } -/* - * Wait at most 2 seconds for flexport arbitration to succeed. - */ -int -ahd_wait_flexport(struct ahd_softc *ahd) -{ - int cnt; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - cnt = 1000000 * 2 / 5; - while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt) - ahd_delay(5); - - if (cnt == 0) - return (ETIMEDOUT); - return (0); -} - /************************* Target Mode ****************************************/ #ifdef AHD_TARGET_MODE cam_status diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h index a3266e066c0..2ceb67f4af2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_inline.h +++ b/drivers/scsi/aic7xxx/aic79xx_inline.h @@ -418,10 +418,6 @@ ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) } /*********************** Miscelaneous Support Functions ***********************/ -static __inline void ahd_complete_scb(struct ahd_softc *ahd, - struct scb *scb); -static __inline void ahd_update_residual(struct ahd_softc *ahd, - struct scb *scb); static __inline struct ahd_initiator_tinfo * ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, @@ -467,32 +463,6 @@ static __inline uint32_t ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb); -static __inline void -ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) -{ - uint32_t sgptr; - - sgptr = ahd_le32toh(scb->hscb->sgptr); - if ((sgptr & SG_STATUS_VALID) != 0) - ahd_handle_scb_status(ahd, scb); - else - ahd_done(ahd, scb); -} - -/* - * Determine whether the sequencer reported a residual - * for this SCB/transaction. - */ -static __inline void -ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) -{ - uint32_t sgptr; - - sgptr = ahd_le32toh(scb->hscb->sgptr); - if ((sgptr & SG_STATUS_VALID) != 0) - ahd_calc_residual(ahd, scb); -} - /* * Return pointers to the transfer negotiation information * for the specified our_id/remote_id pair. diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index f8e60486167..9bfcca5ede0 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -293,7 +293,7 @@ static uint32_t aic79xx_seltime; * force all outstanding transactions to be serviced prior to a new * transaction. */ -uint32_t aic79xx_periodic_otag; +static uint32_t aic79xx_periodic_otag; /* Some storage boxes are using an LSI chip which has a bug making it * impossible to use aic79xx Rev B chip in 320 speeds. The following @@ -773,6 +773,7 @@ struct scsi_host_template aic79xx_driver_template = { #endif .can_queue = AHD_MAX_QUEUE, .this_id = -1, + .max_sectors = 8192, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahd_linux_slave_alloc, @@ -1813,9 +1814,9 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, u_int sense_offset; if (scb->flags & SCB_SENSE) { - sense_size = MIN(sizeof(struct scsi_sense_data) + sense_size = min(sizeof(struct scsi_sense_data) - ahd_get_sense_residual(scb), - sizeof(cmd->sense_buffer)); + (u_long)sizeof(cmd->sense_buffer)); sense_offset = 0; } else { /* @@ -1824,7 +1825,8 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, */ siu = (struct scsi_status_iu_header *) scb->sense_data; - sense_size = MIN(scsi_4btoul(siu->sense_length), + sense_size = min_t(size_t, + scsi_4btoul(siu->sense_length), sizeof(cmd->sense_buffer)); sense_offset = SIU_SENSE_OFFSET(siu); } @@ -2634,8 +2636,22 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) pcomp ? "Enable" : "Disable"); #endif - if (pcomp) + if (pcomp) { + uint8_t precomp; + + if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) { + struct ahd_linux_iocell_opts *iocell_opts; + + iocell_opts = &aic79xx_iocell_info[ahd->unit]; + precomp = iocell_opts->precomp; + } else { + precomp = AIC79XX_DEFAULT_PRECOMP; + } ppr_options |= MSG_EXT_PPR_PCOMP_EN; + AHD_SET_PRECOMP(ahd, precomp); + } else { + AHD_SET_PRECOMP(ahd, 0); + } ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); @@ -2678,7 +2694,25 @@ static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold) ahd_unlock(ahd, &flags); } +static void ahd_linux_get_signalling(struct Scsi_Host *shost) +{ + struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata; + unsigned long flags; + u8 mode; + + ahd_lock(ahd, &flags); + ahd_pause(ahd); + mode = ahd_inb(ahd, SBLKCTL); + ahd_unpause(ahd); + ahd_unlock(ahd, &flags); + if (mode & ENAB40) + spi_signalling(shost) = SPI_SIGNAL_LVD; + else if (mode & ENAB20) + spi_signalling(shost) = SPI_SIGNAL_SE; + else + spi_signalling(shost) = SPI_SIGNAL_UNKNOWN; +} static struct spi_function_template ahd_linux_transport_functions = { .set_offset = ahd_linux_set_offset, @@ -2703,6 +2737,7 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_pcomp_en = 1, .set_hold_mcs = ahd_linux_set_hold_mcs, .show_hold_mcs = 1, + .get_signalling = ahd_linux_get_signalling, }; static int __init diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index fb3d4dd5441..3a67fc578d7 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -506,9 +506,6 @@ struct info_str { int pos; }; -void ahd_format_transinfo(struct info_str *info, - struct ahd_transinfo *tinfo); - /******************************** Locking *************************************/ static __inline void ahd_lockinit(struct ahd_softc *ahd) @@ -582,8 +579,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) #define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ #define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ -extern struct pci_driver aic79xx_pci_driver; - typedef enum { AHD_POWER_STATE_D0, diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 4b535420180..2001fe890e7 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -82,7 +82,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table); -struct pci_driver aic79xx_pci_driver = { +static struct pci_driver aic79xx_pci_driver = { .name = "aic79xx", .probe = ahd_linux_pci_dev_probe, .remove = ahd_linux_pci_dev_remove, diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 14850f31aaf..c07735819cd 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -97,7 +97,7 @@ static ahd_device_setup_t ahd_aic7901A_setup; static ahd_device_setup_t ahd_aic7902_setup; static ahd_device_setup_t ahd_aic790X_setup; -struct ahd_pci_identity ahd_pci_ident_table [] = +static struct ahd_pci_identity ahd_pci_ident_table [] = { /* aic7901 based controllers */ { @@ -201,7 +201,7 @@ struct ahd_pci_identity ahd_pci_ident_table [] = } }; -const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table); +static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table); #define DEVCONFIG 0x40 #define PCIXINITPAT 0x0000E000ul @@ -245,6 +245,7 @@ static int ahd_check_extport(struct ahd_softc *ahd); static void ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control); static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat); +static void ahd_pci_intr(struct ahd_softc *ahd); struct ahd_pci_identity * ahd_find_pci_device(ahd_dev_softc_t pci) @@ -757,7 +758,7 @@ static const char *pci_status_strings[] = "%s: Address or Write Phase Parity Error Detected in %s.\n" }; -void +static void ahd_pci_intr(struct ahd_softc *ahd) { uint8_t pci_status[8]; diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index c5f0ee59150..6b28bebcbca 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -136,7 +136,7 @@ copy_info(struct info_str *info, char *fmt, ...) return (len); } -void +static void ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) { u_int speed; diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 62ff8c3dc2b..954c7c24501 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -54,14 +54,6 @@ struct scb_platform_data; struct seeprom_descriptor; /****************************** Useful Macros *********************************/ -#ifndef MAX -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - #ifndef TRUE #define TRUE 1 #endif @@ -1135,8 +1127,6 @@ struct ahc_pci_identity { char *name; ahc_device_setup_t *setup; }; -extern struct ahc_pci_identity ahc_pci_ident_table[]; -extern const u_int ahc_num_pci_devs; /***************************** VL/EISA Declarations ***************************/ struct aic7770_identity { @@ -1289,6 +1279,7 @@ typedef enum { } ahc_queue_alg; void ahc_set_tags(struct ahc_softc *ahc, + struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, ahc_queue_alg alg); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 93e4e40944b..50ef785224d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -1671,7 +1671,7 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc, transinfo = &tinfo->goal; *ppr_options &= transinfo->ppr_options; if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) { - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + maxsync = max(maxsync, (u_int)AHC_SYNCRATE_ULTRA2); *ppr_options &= ~MSG_EXT_PPR_DT_REQ; } if (transinfo->period == 0) { @@ -1679,7 +1679,7 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc, *ppr_options = 0; return (NULL); } - *period = MAX(*period, transinfo->period); + *period = max(*period, (u_int)transinfo->period); return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); } @@ -1804,12 +1804,12 @@ ahc_validate_offset(struct ahc_softc *ahc, else maxoffset = MAX_OFFSET_8BIT; } - *offset = MIN(*offset, maxoffset); + *offset = min(*offset, maxoffset); if (tinfo != NULL) { if (role == ROLE_TARGET) - *offset = MIN(*offset, tinfo->user.offset); + *offset = min(*offset, (u_int)tinfo->user.offset); else - *offset = MIN(*offset, tinfo->goal.offset); + *offset = min(*offset, (u_int)tinfo->goal.offset); } } @@ -1835,9 +1835,9 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, } if (tinfo != NULL) { if (role == ROLE_TARGET) - *bus_width = MIN(tinfo->user.width, *bus_width); + *bus_width = min((u_int)tinfo->user.width, *bus_width); else - *bus_width = MIN(tinfo->goal.width, *bus_width); + *bus_width = min((u_int)tinfo->goal.width, *bus_width); } } @@ -1986,7 +1986,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, tinfo->curr.ppr_options = ppr_options; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz%s, " @@ -2056,7 +2056,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, tinfo->curr.width = width; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, @@ -2074,12 +2074,14 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, * Update the current state of tagged queuing for a given target. */ void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - ahc_queue_alg alg) +ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd, + struct ahc_devinfo *devinfo, ahc_queue_alg alg) { - ahc_platform_set_tags(ahc, devinfo, alg); + struct scsi_device *sdev = cmd->device; + + ahc_platform_set_tags(ahc, sdev, devinfo, alg); ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG, &alg); + devinfo->lun, AC_TRANSFER_NEG); } /* @@ -3489,7 +3491,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) printf("(%s:%c:%d:%d): refuses tagged commands. " "Performing non-tagged I/O\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE); mask = ~0x23; } else { printf("(%s:%c:%d:%d): refuses %s tagged commands. " @@ -3497,7 +3499,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, tag_type == MSG_ORDERED_TASK ? "ordered" : "head of queue"); - ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_BASIC); mask = ~0x03; } @@ -3763,7 +3765,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (status != CAM_SEL_TIMEOUT) ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); if (message != NULL && (verbose_level <= bootverbose)) @@ -4406,7 +4408,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) physaddr = sg_map->sg_physaddr; newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); - newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); + newcount = min(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); for (i = 0; i < newcount; i++) { struct scb_platform_data *pdata; #ifndef __linux__ @@ -6018,7 +6020,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); + CAM_LUN_WILDCARD, AC_BUS_RESET); /* * Revert to async/narrow transfers until we renegotiate. @@ -6442,7 +6444,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) if (skip_addr > i) { int end_addr; - end_addr = MIN(address, skip_addr); + end_addr = min(address, skip_addr); address_offset += end_addr - i; i = skip_addr; } else { diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 43ab753d273..660f26e23a3 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -328,7 +328,7 @@ static uint32_t aic7xxx_seltime; * force all outstanding transactions to be serviced prior to a new * transaction. */ -uint32_t aic7xxx_periodic_otag; +static uint32_t aic7xxx_periodic_otag; /* * Module information and settable options. @@ -512,7 +512,6 @@ ahc_linux_target_alloc(struct scsi_target *starget) struct seeprom_config *sc = ahc->seep_config; unsigned long flags; struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget); - struct ahc_linux_target *targ = scsi_transport_target_data(starget); unsigned short scsirate; struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; @@ -533,7 +532,6 @@ ahc_linux_target_alloc(struct scsi_target *starget) BUG_ON(*ahc_targp != NULL); *ahc_targp = starget; - memset(targ, 0, sizeof(*targ)); if (sc) { int maxsync = AHC_SYNCRATE_DT; @@ -594,14 +592,11 @@ ahc_linux_slave_alloc(struct scsi_device *sdev) struct ahc_softc *ahc = *((struct ahc_softc **)sdev->host->hostdata); struct scsi_target *starget = sdev->sdev_target; - struct ahc_linux_target *targ = scsi_transport_target_data(starget); struct ahc_linux_device *dev; if (bootverbose) printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id); - BUG_ON(targ->sdev[sdev->lun] != NULL); - dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); @@ -618,8 +613,6 @@ ahc_linux_slave_alloc(struct scsi_device *sdev) */ dev->maxtags = 0; - targ->sdev[sdev->lun] = sdev; - spi_period(starget) = 0; return 0; @@ -644,22 +637,6 @@ ahc_linux_slave_configure(struct scsi_device *sdev) return 0; } -static void -ahc_linux_slave_destroy(struct scsi_device *sdev) -{ - struct ahc_softc *ahc; - struct ahc_linux_device *dev = scsi_transport_device_data(sdev); - struct ahc_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); - - ahc = *((struct ahc_softc **)sdev->host->hostdata); - if (bootverbose) - printf("%s: Slave Destroy %d\n", ahc_name(ahc), sdev->id); - - BUG_ON(dev->active); - - targ->sdev[sdev->lun] = NULL; -} - #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. @@ -777,11 +754,11 @@ struct scsi_host_template aic7xxx_driver_template = { #endif .can_queue = AHC_MAX_QUEUE, .this_id = -1, + .max_sectors = 8192, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, - .slave_destroy = ahc_linux_slave_destroy, .target_alloc = ahc_linux_target_alloc, .target_destroy = ahc_linux_target_destroy, }; @@ -1203,21 +1180,13 @@ void ahc_platform_free(struct ahc_softc *ahc) { struct scsi_target *starget; - int i, j; + int i; if (ahc->platform_data != NULL) { /* destroy all of the device and target objects */ for (i = 0; i < AHC_NUM_TARGETS; i++) { starget = ahc->platform_data->starget[i]; if (starget != NULL) { - for (j = 0; j < AHC_NUM_LUNS; j++) { - struct ahc_linux_target *targ = - scsi_transport_target_data(starget); - - if (targ->sdev[j] == NULL) - continue; - targ->sdev[j] = NULL; - } ahc->platform_data->starget[i] = NULL; } } @@ -1251,24 +1220,13 @@ ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb) } void -ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - ahc_queue_alg alg) +ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, + struct ahc_devinfo *devinfo, ahc_queue_alg alg) { - struct scsi_target *starget; - struct ahc_linux_target *targ; struct ahc_linux_device *dev; - struct scsi_device *sdev; - u_int target_offset; int was_queuing; int now_queuing; - target_offset = devinfo->target; - if (devinfo->channel != 'A') - target_offset += 8; - starget = ahc->platform_data->starget[target_offset]; - targ = scsi_transport_target_data(starget); - BUG_ON(targ == NULL); - sdev = targ->sdev[devinfo->lun]; if (sdev == NULL) return; dev = scsi_transport_device_data(sdev); @@ -1401,11 +1359,15 @@ ahc_linux_device_queue_depth(struct scsi_device *sdev) tags = ahc_linux_user_tagdepth(ahc, &devinfo); if (tags != 0 && sdev->tagged_supported != 0) { - ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); + ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_TAGGED); + ahc_send_async(ahc, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); ahc_print_devinfo(ahc, &devinfo); printf("Tagged Queuing enabled. Depth %d\n", tags); } else { - ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE); + ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE); + ahc_send_async(ahc, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); } } @@ -1629,7 +1591,7 @@ ahc_platform_flushwork(struct ahc_softc *ahc) void ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code, void *arg) + u_int target, u_int lun, ac_code code) { switch (code) { case AC_TRANSFER_NEG: @@ -1875,9 +1837,9 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, if (scb->flags & SCB_SENSE) { u_int sense_size; - sense_size = MIN(sizeof(struct scsi_sense_data) + sense_size = min(sizeof(struct scsi_sense_data) - ahc_get_sense_residual(scb), - sizeof(cmd->sense_buffer)); + (u_long)sizeof(cmd->sense_buffer)); memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), sense_size); if (sense_size < sizeof(cmd->sense_buffer)) @@ -1946,7 +1908,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, } ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); ahc_set_scsi_status(scb, SCSI_STATUS_OK); - ahc_platform_set_tags(ahc, &devinfo, + ahc_platform_set_tags(ahc, sdev, &devinfo, (dev->flags & AHC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); break; @@ -1957,7 +1919,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, */ dev->openings = 1; ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); - ahc_platform_set_tags(ahc, &devinfo, + ahc_platform_set_tags(ahc, sdev, &devinfo, (dev->flags & AHC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); break; @@ -2599,8 +2561,6 @@ ahc_linux_init(void) if (!ahc_linux_transport_template) return -ENODEV; - scsi_transport_reserve_target(ahc_linux_transport_template, - sizeof(struct ahc_linux_target)); scsi_transport_reserve_device(ahc_linux_transport_template, sizeof(struct ahc_linux_device)); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index a87a4ce090d..85ae5d836fa 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -256,7 +256,6 @@ typedef enum { AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ } ahc_linux_dev_flags; -struct ahc_linux_target; struct ahc_linux_device { /* * The number of transactions currently @@ -329,12 +328,6 @@ struct ahc_linux_device { #define AHC_OTAG_THRESH 500 }; -struct ahc_linux_target { - struct scsi_device *sdev[AHC_NUM_LUNS]; - struct ahc_transinfo last_tinfo; - struct ahc_softc *ahc; -}; - /********************* Definitions Required by the Core ***********************/ /* * Number of SG segments we require. So long as the S/G segments for @@ -533,8 +526,6 @@ ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e -extern struct pci_driver aic7xxx_pci_driver; - typedef enum { AHC_POWER_STATE_D0, @@ -824,7 +815,7 @@ ahc_freeze_scb(struct scb *scb) } } -void ahc_platform_set_tags(struct ahc_softc *ahc, +void ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, struct ahc_devinfo *devinfo, ahc_queue_alg); int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, @@ -834,7 +825,7 @@ irqreturn_t void ahc_platform_flushwork(struct ahc_softc *ahc); void ahc_done(struct ahc_softc*, struct scb*); void ahc_send_async(struct ahc_softc *, char channel, - u_int target, u_int lun, ac_code, void *); + u_int target, u_int lun, ac_code); void ahc_print_path(struct ahc_softc *, struct scb *); void ahc_platform_dump_card_state(struct ahc_softc *ahc); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index d20ca514e9f..ea5687df732 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -130,7 +130,7 @@ static struct pci_device_id ahc_linux_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table); -struct pci_driver aic7xxx_pci_driver = { +static struct pci_driver aic7xxx_pci_driver = { .name = "aic7xxx", .probe = ahc_linux_pci_dev_probe, .remove = ahc_linux_pci_dev_remove, diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 63cab2d7455..09c8172c9e5 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -168,7 +168,7 @@ static ahc_device_setup_t ahc_aha394XX_setup; static ahc_device_setup_t ahc_aha494XX_setup; static ahc_device_setup_t ahc_aha398XX_setup; -struct ahc_pci_identity ahc_pci_ident_table [] = +static struct ahc_pci_identity ahc_pci_ident_table [] = { /* aic7850 based controllers */ { @@ -559,7 +559,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] = } }; -const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table); +static const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table); #define AHC_394X_SLOT_CHANNEL_A 4 #define AHC_394X_SLOT_CHANNEL_B 5 diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 5914b4aa4a8..99e5443e753 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -182,7 +182,6 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info, u_int our_id, char channel, u_int target_id, u_int target_offset) { - struct ahc_linux_target *targ; struct scsi_target *starget; struct ahc_initiator_tinfo *tinfo; struct ahc_tmode_tstate *tstate; @@ -198,7 +197,6 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info, starget = ahc->platform_data->starget[target_offset]; if (!starget) return; - targ = scsi_transport_target_data(starget); copy_info(info, "\tGoal: "); ahc_format_transinfo(info, &tinfo->goal); @@ -208,7 +206,7 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info, for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct scsi_device *sdev; - sdev = targ->sdev[lun]; + sdev = scsi_device_lookup_by_target(starget, lun); if (sdev == NULL) continue; @@ -383,11 +381,11 @@ ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, } copy_info(&info, "\n"); - max_targ = 15; + max_targ = 16; if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) - max_targ = 7; + max_targ = 8; - for (i = 0; i <= max_targ; i++) { + for (i = 0; i < max_targ; i++) { u_int our_id; u_int target_id; char channel; diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index bcd7fffab90..46eed10b25d 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -2646,7 +2646,7 @@ static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p) while (p->completeq.head != NULL) { cmd = p->completeq.head; - p->completeq.head = (struct scsi_Cmnd *) cmd->host_scribble; + p->completeq.head = (struct scsi_cmnd *) cmd->host_scribble; cmd->host_scribble = NULL; cmd->scsi_done(cmd); } diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 3c2d7a37993..af7e0113436 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -112,6 +112,21 @@ static int asd_init_phy(struct asd_phy *phy) return 0; } +static void asd_init_ports(struct asd_ha_struct *asd_ha) +{ + int i; + + spin_lock_init(&asd_ha->asd_ports_lock); + for (i = 0; i < ASD_MAX_PHYS; i++) { + struct asd_port *asd_port = &asd_ha->asd_ports[i]; + + memset(asd_port->sas_addr, 0, SAS_ADDR_SIZE); + memset(asd_port->attached_sas_addr, 0, SAS_ADDR_SIZE); + asd_port->phy_mask = 0; + asd_port->num_phys = 0; + } +} + static int asd_init_phys(struct asd_ha_struct *asd_ha) { u8 i; @@ -121,6 +136,7 @@ static int asd_init_phys(struct asd_ha_struct *asd_ha) struct asd_phy *phy = &asd_ha->phys[i]; phy->phy_desc = &asd_ha->hw_prof.phy_desc[i]; + phy->asd_port = NULL; phy->sas_phy.enabled = 0; phy->sas_phy.id = i; @@ -658,6 +674,8 @@ int asd_init_hw(struct asd_ha_struct *asd_ha) goto Out; } + asd_init_ports(asd_ha); + err = asd_init_scbs(asd_ha); if (err) { asd_printk("couldn't initialize scbs for %s\n", diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index 14319d1d680..c6c3d18222f 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -46,6 +46,7 @@ #define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410 #define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412 #define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E +#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F #define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430 #define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432 #define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E @@ -192,6 +193,16 @@ struct asd_seq_data { struct asd_ascb **escb_arr; /* array of pointers to escbs */ }; +/* This is an internal port structure. These are used to get accurate + * phy_mask for updating DDB 0. + */ +struct asd_port { + u8 sas_addr[SAS_ADDR_SIZE]; + u8 attached_sas_addr[SAS_ADDR_SIZE]; + u32 phy_mask; + int num_phys; +}; + /* This is the Host Adapter structure. It describes the hardware * SAS adapter. */ @@ -210,6 +221,8 @@ struct asd_ha_struct { struct hw_profile hw_prof; struct asd_phy phys[ASD_MAX_PHYS]; + spinlock_t asd_ports_lock; + struct asd_port asd_ports[ASD_MAX_PHYS]; struct asd_sas_port ports[ASD_MAX_PHYS]; struct dma_pool *scb_pool; diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 3a5bbba3976..42302ef05ee 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -795,8 +795,6 @@ static void asd_remove_driver_attrs(struct device_driver *driver) } static struct sas_domain_function_template aic94xx_transport_functions = { - .lldd_port_formed = asd_update_port_links, - .lldd_dev_found = asd_dev_found, .lldd_dev_gone = asd_dev_gone, @@ -823,6 +821,8 @@ static const struct pci_device_id aic94xx_pci_table[] __devinitdata = { 0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E), 0, 0, 1}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F), + 0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30), 0, 0, 2}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32), diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h index 64d23171234..9050e93bfd5 100644 --- a/drivers/scsi/aic94xx/aic94xx_sas.h +++ b/drivers/scsi/aic94xx/aic94xx_sas.h @@ -733,6 +733,7 @@ struct asd_phy { struct sas_identify_frame *identify_frame; struct asd_dma_tok *id_frm_tok; + struct asd_port *asd_port; u8 frame_rcvd[ASD_EDB_SIZE]; }; diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 52c6ea4fbf7..14d5d8c2ee1 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -169,6 +169,70 @@ static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr) } } +static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) +{ + int i; + struct asd_port *free_port = NULL; + struct asd_port *port; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + unsigned long flags; + + spin_lock_irqsave(&asd_ha->asd_ports_lock, flags); + if (!phy->asd_port) { + for (i = 0; i < ASD_MAX_PHYS; i++) { + port = &asd_ha->asd_ports[i]; + + /* Check for wide port */ + if (port->num_phys > 0 && + memcmp(port->sas_addr, sas_phy->sas_addr, + SAS_ADDR_SIZE) == 0 && + memcmp(port->attached_sas_addr, + sas_phy->attached_sas_addr, + SAS_ADDR_SIZE) == 0) { + break; + } + + /* Find a free port */ + if (port->num_phys == 0 && free_port == NULL) { + free_port = port; + } + } + + /* Use a free port if this doesn't form a wide port */ + if (i >= ASD_MAX_PHYS) { + port = free_port; + BUG_ON(!port); + memcpy(port->sas_addr, sas_phy->sas_addr, + SAS_ADDR_SIZE); + memcpy(port->attached_sas_addr, + sas_phy->attached_sas_addr, + SAS_ADDR_SIZE); + } + port->num_phys++; + port->phy_mask |= (1U << sas_phy->id); + phy->asd_port = port; + } + ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n", + __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id); + asd_update_port_links(asd_ha, phy); + spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); +} + +static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) +{ + struct asd_port *port = phy->asd_port; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + unsigned long flags; + + spin_lock_irqsave(&asd_ha->asd_ports_lock, flags); + if (port) { + port->num_phys--; + port->phy_mask &= ~(1U << sas_phy->id); + phy->asd_port = NULL; + } + spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); +} + static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, struct done_list_struct *dl, int edb_id, int phy_id) @@ -188,6 +252,7 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); asd_dump_frame_rcvd(phy, dl); + asd_form_port(ascb->ha, phy); sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); } @@ -198,6 +263,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb, struct asd_ha_struct *asd_ha = ascb->ha; struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; + struct asd_phy *phy = &asd_ha->phys[phy_id]; u8 lr_error = dl->status_block[1]; u8 retries_left = dl->status_block[2]; @@ -222,6 +288,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb, asd_turn_led(asd_ha, phy_id, 0); sas_phy_disconnected(sas_phy); + asd_deform_port(asd_ha, phy); sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); if (retries_left == 0) { @@ -249,6 +316,8 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, unsigned long flags; struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; + struct asd_ha_struct *asd_ha = ascb->ha; + struct asd_phy *phy = &asd_ha->phys[phy_id]; u8 reg = dl->status_block[1]; u32 cont = dl->status_block[2] << ((reg & 3)*8); @@ -285,6 +354,7 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, phy_id); /* The sequencer disables all phys on that port. * We have to re-enable the phys ourselves. */ + asd_deform_port(asd_ha, phy); sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); break; @@ -385,6 +455,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, u8 sb_opcode = dl->status_block[0]; int phy_id = sb_opcode & DL_PHY_MASK; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; + struct asd_phy *phy = &asd_ha->phys[phy_id]; if (edb > 6 || edb < 0) { ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", @@ -497,6 +568,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, asd_turn_led(asd_ha, phy_id, 0); /* the device is gone */ sas_phy_disconnected(sas_phy); + asd_deform_port(asd_ha, phy); sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); break; default: diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index 83574b5b4e6..de7c04d4254 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -630,10 +630,6 @@ static int asd_flash_getid(struct asd_ha_struct *asd_ha) reg = asd_read_reg_dword(asd_ha, EXSICNFGR); - if (!(reg & FLASHEX)) { - ASD_DPRINTK("flash doesn't exist\n"); - return -ENOENT; - } if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR, &asd_ha->hw_prof.flash.bar)) { asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n", diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index 56e4b3ba6a0..845112539d0 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -1369,10 +1369,9 @@ int asd_start_seqs(struct asd_ha_struct *asd_ha) * port_map_by_links is also used as the conn_mask byte in the * initiator/target port DDB. */ -void asd_update_port_links(struct asd_sas_phy *sas_phy) +void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy) { - struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha; - const u8 phy_mask = (u8) sas_phy->port->phy_mask; + const u8 phy_mask = (u8) phy->asd_port->phy_mask; u8 phy_is_up; u8 mask; int i, err; diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index 42281c36153..9e715e5496a 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h @@ -64,7 +64,7 @@ int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); int asd_init_seqs(struct asd_ha_struct *asd_ha); int asd_start_seqs(struct asd_ha_struct *asd_ha); -void asd_update_port_links(struct asd_sas_phy *phy); +void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy); #endif #endif diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h index b3fa7ed71fa..5a49216fe4c 100644 --- a/drivers/scsi/dpt/dpti_i2o.h +++ b/drivers/scsi/dpt/dpti_i2o.h @@ -49,7 +49,7 @@ #include <linux/wait.h> typedef wait_queue_head_t adpt_wait_queue_head_t; -#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait) +#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait) typedef wait_queue_t adpt_wait_queue_t; /* diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 0d5713dfa20..54756722dd5 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -82,7 +82,7 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <asm/io.h> +#include <linux/io.h> #include "scsi.h" #include <scsi/scsi_host.h> #include "dtc.h" diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 811d8840707..2dbb66d2f0a 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -203,7 +203,7 @@ static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id) irqreturn_t ret; spin_lock_irqsave(dev->host_lock, flags); - ret = eata_pio_int_handler(irq, dev_id, regs); + ret = eata_pio_int_handler(irq, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return ret; } diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 41b05fc4538..5d4ea6f7795 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -278,9 +278,9 @@ #include <linux/pci.h> #include <linux/stat.h> #include <linux/delay.h> +#include <linux/io.h> #include <scsi/scsicam.h> -#include <asm/io.h> #include <asm/system.h> #include <scsi/scsi.h> @@ -387,6 +387,7 @@ static void __iomem * bios_mem; static int bios_major; static int bios_minor; static int PCI_bus; +static struct pci_dev *PCI_dev; static int Quantum; /* Quantum board variant */ static int interrupt_level; static volatile int in_command; @@ -812,9 +813,10 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_ PCI_DEVICE_ID_FD_36C70 ); #endif - if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL) + if ((pdev = pci_get_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL) return 0; - if (pci_enable_device(pdev)) return 0; + if (pci_enable_device(pdev)) + goto fail; #if DEBUG_DETECT printk( "scsi: <fdomain> TMC-3260 detect:" @@ -831,7 +833,7 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_ pci_irq = pdev->irq; if (!request_region( pci_base, 0x10, "fdomain" )) - return 0; + goto fail; /* Now we have the I/O base address and interrupt from the PCI configuration registers. */ @@ -848,17 +850,22 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_ if (!fdomain_is_valid_port(pci_base)) { printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" ); release_region(pci_base, 0x10); - return 0; + goto fail; } /* Fill in a few global variables. Ugh. */ bios_major = bios_minor = -1; PCI_bus = 1; + PCI_dev = pdev; Quantum = 0; bios_base = 0; return 1; +fail: + pci_dev_put(pdev); + return 0; } + #endif struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ) @@ -909,8 +916,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ) if (setup_called) { printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n"); } - release_region(port_base, 0x10); - return NULL; + goto fail; } if (this_id) { @@ -942,8 +948,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ) /* Log IRQ with kernel */ if (!interrupt_level) { printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" ); - release_region(port_base, 0x10); - return NULL; + goto fail; } else { /* Register the IRQ with the kernel */ @@ -964,11 +969,14 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ) printk(KERN_ERR " Send mail to faith@acm.org\n" ); } printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" ); - release_region(port_base, 0x10); - return NULL; + goto fail; } } return shpnt; +fail: + pci_dev_put(pdev); + release_region(port_base, 0x10); + return NULL; } static int fdomain_16x0_detect(struct scsi_host_template *tpnt) @@ -1714,6 +1722,8 @@ static int fdomain_16x0_release(struct Scsi_Host *shpnt) free_irq(shpnt->irq, shpnt); if (shpnt->io_port && shpnt->n_io_port) release_region(shpnt->io_port, shpnt->n_io_port); + if (PCI_bus) + pci_dev_put(PCI_dev); return 0; } @@ -1736,6 +1746,15 @@ struct scsi_host_template fdomain_driver_template = { }; #ifndef PCMCIA + +static struct pci_device_id fdomain_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { } +}; +MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl); + #define driver_template fdomain_driver_template #include "scsi_module.c" + #endif diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 4bc14ad92e2..4c698a71f66 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -3531,7 +3531,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) IStatus &= ~0x80; #ifdef INT_COAL if (coalesced) - ha->status = pcs->ext_status && 0xffff; + ha->status = pcs->ext_status & 0xffff; else #endif ha->status = gdth_readw(&dp6m_ptr->i960r.status); @@ -3543,7 +3543,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) if (coalesced) { ha->info = pcs->info0; ha->info2 = pcs->info1; - ha->service = (pcs->ext_status >> 16) && 0xffff; + ha->service = (pcs->ext_status >> 16) & 0xffff; } else #endif { diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 669ea4fff16..fbc1d5c3b0a 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1213,7 +1213,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, "ibmvscsi: Re-enabling adapter!\n"); purge_requests(hostdata, DID_REQUEUE); if ((ibmvscsi_reenable_crq_queue(&hostdata->queue, - hostdata) == 0) || + hostdata)) || (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0))) { atomic_set(&hostdata->request_limit, diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 2d95ac9c32c..e31f6122106 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1153,7 +1153,7 @@ static int __imm_attach(struct parport *pb) { struct Scsi_Host *host; imm_struct *dev; - DECLARE_WAIT_QUEUE_HEAD(waiting); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); int ports; int modes, ppb; diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 911f2ff4a1f..afed293dd7b 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -142,8 +142,6 @@ #define i91u_MAXQUEUE 2 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a" -#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */ -#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */ #define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */ #define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */ #define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */ @@ -171,13 +169,16 @@ static int setup_debug = 0; static void i91uSCBPost(BYTE * pHcb, BYTE * pScb); -static const PCI_ID i91u_pci_devices[] = { - { INI_VENDOR_ID, I950_DEVICE_ID }, - { INI_VENDOR_ID, I940_DEVICE_ID }, - { INI_VENDOR_ID, I935_DEVICE_ID }, - { INI_VENDOR_ID, I920_DEVICE_ID }, - { DMX_VENDOR_ID, I920_DEVICE_ID }, +/* PCI Devices supported by this driver */ +static struct pci_device_id i91u_pci_devices[] __devinitdata = { + { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } }; +MODULE_DEVICE_TABLE(pci, i91u_pci_devices); #define DEBUG_INTERRUPT 0 #define DEBUG_QUEUE 0 @@ -2771,7 +2772,7 @@ static int tul_NewReturnNumberOfAdapters(void) for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++) { - while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) { + while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) { if (pci_enable_device(pDev)) continue; pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0a9dbc59663..d0b139cccbb 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -415,8 +415,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_solicit_data_init(conn, ctask, r2t); tcp_ctask->exp_r2tsn = r2tsn + 1; - tcp_ctask->xmstate |= XMSTATE_SOL_HDR; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); + tcp_ctask->xmstate |= XMSTATE_SOL_HDR; list_move_tail(&ctask->running, &conn->xmitqueue); scsi_queue_work(session->host, &conn->xmitwork); @@ -1627,9 +1627,12 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) { tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR; tcp_ctask->xmstate |= XMSTATE_SOL_DATA; - if (!tcp_ctask->r2t) + if (!tcp_ctask->r2t) { + spin_lock_bh(&session->lock); __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t, sizeof(void*)); + spin_unlock_bh(&session->lock); + } send_hdr: r2t = tcp_ctask->r2t; dtask = &r2t->dtask; @@ -1816,21 +1819,14 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - int digest = 0; - - if (conn->hdrdgst_en || conn->datadgst_en) - digest = 1; iscsi_tcp_release_conn(conn); iscsi_conn_teardown(cls_conn); - /* now free tcp_conn */ - if (digest) { - if (tcp_conn->tx_hash.tfm) - crypto_free_hash(tcp_conn->tx_hash.tfm); - if (tcp_conn->rx_hash.tfm) - crypto_free_hash(tcp_conn->rx_hash.tfm); - } + if (tcp_conn->tx_hash.tfm) + crypto_free_hash(tcp_conn->tx_hash.tfm); + if (tcp_conn->rx_hash.tfm) + crypto_free_hash(tcp_conn->rx_hash.tfm); kfree(tcp_conn); } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c542d0e95e6..5d886218948 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -481,8 +481,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, break; case ISCSI_OP_ASYNC_EVENT: conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - /* we need sth like iscsi_async_event_rsp() */ - rc = ISCSI_ERR_BAD_OPCODE; + if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) + rc = ISCSI_ERR_CONN_FAILED; break; default: rc = ISCSI_ERR_BAD_OPCODE; @@ -578,6 +578,27 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) } EXPORT_SYMBOL_GPL(iscsi_conn_failure); +static int iscsi_xmit_imm_task(struct iscsi_conn *conn) +{ + struct iscsi_hdr *hdr = conn->mtask->hdr; + int rc, was_logout = 0; + + if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { + conn->session->state = ISCSI_STATE_IN_RECOVERY; + iscsi_block_session(session_to_cls(conn->session)); + was_logout = 1; + } + rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); + if (rc) + return rc; + + if (was_logout) { + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + return -ENODATA; + } + return 0; +} + /** * iscsi_data_xmit - xmit any command into the scheduled connection * @conn: iscsi connection @@ -623,7 +644,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) conn->ctask = NULL; } if (conn->mtask) { - rc = tt->xmit_mgmt_task(conn, conn->mtask); + rc = iscsi_xmit_imm_task(conn); if (rc) goto again; /* done with this in-progress mtask */ @@ -638,7 +659,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); spin_unlock_bh(&conn->session->lock); - rc = tt->xmit_mgmt_task(conn, conn->mtask); + rc = iscsi_xmit_imm_task(conn); if (rc) goto again; } @@ -661,8 +682,6 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) spin_unlock_bh(&conn->session->lock); rc = tt->xmit_cmd_task(conn, conn->ctask); - if (rc) - goto again; spin_lock_bh(&conn->session->lock); __iscsi_put_ctask(conn->ctask); @@ -778,6 +797,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) } conn = session->leadconn; + if (!conn) { + reason = FAILURE_SESSION_FREED; + goto fault; + } if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*))) { @@ -952,13 +975,13 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) if (session->state == ISCSI_STATE_TERMINATE) { failed: debug_scsi("failing host reset: session terminated " - "[CID %d age %d]", conn->id, session->age); + "[CID %d age %d]\n", conn->id, session->age); spin_unlock_bh(&session->lock); return FAILED; } if (sc->SCp.phase == session->age) { - debug_scsi("failing connection CID %d due to SCSI host reset", + debug_scsi("failing connection CID %d due to SCSI host reset\n", conn->id); fail_session = 1; } @@ -1031,7 +1054,8 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, NULL, 0); if (rc) { iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc); + debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt, + rc); return rc; } @@ -1048,7 +1072,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, conn->tmabort_timer.function = iscsi_tmabort_timedout; conn->tmabort_timer.data = (unsigned long)ctask; add_timer(&conn->tmabort_timer); - debug_scsi("abort set timeout [itt 0x%x]", ctask->itt); + debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); } spin_unlock_bh(&session->lock); mutex_unlock(&conn->xmitmutex); @@ -1377,7 +1401,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit, } spin_lock_init(&session->lock); - INIT_LIST_HEAD(&session->connections); /* initialize immediate command pool */ if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, @@ -1580,16 +1603,11 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) kfree(conn->persistent_address); __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, sizeof(void*)); - list_del(&conn->item); - if (list_empty(&session->connections)) + if (session->leadconn == conn) { session->leadconn = NULL; - if (session->leadconn && session->leadconn == conn) - session->leadconn = container_of(session->connections.next, - struct iscsi_conn, item); - - if (session->leadconn == NULL) /* no connections exits.. reset sequencing */ session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; + } spin_unlock_bh(&session->lock); kfifo_free(conn->immqueue); @@ -1777,32 +1795,12 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, int is_leading) { struct iscsi_session *session = class_to_transport_session(cls_session); - struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data; + struct iscsi_conn *conn = cls_conn->dd_data; - /* lookup for existing connection */ spin_lock_bh(&session->lock); - list_for_each_entry(tmp, &session->connections, item) { - if (tmp == conn) { - if (conn->c_stage != ISCSI_CONN_STOPPED || - conn->stop_stage == STOP_CONN_TERM) { - printk(KERN_ERR "iscsi: can't bind " - "non-stopped connection (%d:%d)\n", - conn->c_stage, conn->stop_stage); - spin_unlock_bh(&session->lock); - return -EIO; - } - break; - } - } - if (tmp != conn) { - /* bind new iSCSI connection to session */ - conn->session = session; - list_add(&conn->item, &session->connections); - } - spin_unlock_bh(&session->lock); - if (is_leading) session->leadconn = conn; + spin_unlock_bh(&session->lock); /* * Unblock xmitworker(), Login Phase will pass through. diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 30b8014bcc7..e34a9343549 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -71,55 +71,65 @@ static void smp_task_done(struct sas_task *task) static int smp_execute_task(struct domain_device *dev, void *req, int req_size, void *resp, int resp_size) { - int res; - struct sas_task *task = sas_alloc_task(GFP_KERNEL); + int res, retry; + struct sas_task *task = NULL; struct sas_internal *i = to_sas_internal(dev->port->ha->core.shost->transportt); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - sg_init_one(&task->smp_task.smp_req, req, req_size); - sg_init_one(&task->smp_task.smp_resp, resp, resp_size); + for (retry = 0; retry < 3; retry++) { + task = sas_alloc_task(GFP_KERNEL); + if (!task) + return -ENOMEM; - task->task_done = smp_task_done; + task->dev = dev; + task->task_proto = dev->tproto; + sg_init_one(&task->smp_task.smp_req, req, req_size); + sg_init_one(&task->smp_task.smp_resp, resp, resp_size); - task->timer.data = (unsigned long) task; - task->timer.function = smp_task_timedout; - task->timer.expires = jiffies + SMP_TIMEOUT*HZ; - add_timer(&task->timer); + task->task_done = smp_task_done; - res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); + task->timer.data = (unsigned long) task; + task->timer.function = smp_task_timedout; + task->timer.expires = jiffies + SMP_TIMEOUT*HZ; + add_timer(&task->timer); - if (res) { - del_timer(&task->timer); - SAS_DPRINTK("executing SMP task failed:%d\n", res); - goto ex_err; - } + res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); - wait_for_completion(&task->completion); - res = -ETASK; - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - SAS_DPRINTK("smp task timed out or aborted\n"); - i->dft->lldd_abort_task(task); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - SAS_DPRINTK("SMP task aborted and not done\n"); + if (res) { + del_timer(&task->timer); + SAS_DPRINTK("executing SMP task failed:%d\n", res); goto ex_err; } + + wait_for_completion(&task->completion); + res = -ETASK; + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + SAS_DPRINTK("smp task timed out or aborted\n"); + i->dft->lldd_abort_task(task); + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + SAS_DPRINTK("SMP task aborted and not done\n"); + goto ex_err; + } + } + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAM_GOOD) { + res = 0; + break; + } else { + SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " + "status 0x%x\n", __FUNCTION__, + SAS_ADDR(dev->sas_addr), + task->task_status.resp, + task->task_status.stat); + sas_free_task(task); + task = NULL; + } } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_GOOD) - res = 0; - else - SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " - "status 0x%x\n", __FUNCTION__, - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); ex_err: - sas_free_task(task); + BUG_ON(retry == 3 && task != NULL); + if (task != NULL) { + sas_free_task(task); + } return res; } diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 9496e87c135..2a4e02e7a39 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -594,7 +594,8 @@ lpfc_soft_wwpn_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", phba->cfg_soft_wwpn); + return snprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long)phba->cfg_soft_wwpn); } diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 1b53afb1cb5..3add7c23785 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -188,7 +188,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl, if (!mp->virt) { kfree(mp); - lpfc_free_ct_rsp(phba, mlist); + if (mlist) + lpfc_free_ct_rsp(phba, mlist); return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d586c3d3b0d..19c79a0549a 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -305,7 +305,7 @@ lpfc_do_work(void *p) { struct lpfc_hba *phba = p; int rc; - DECLARE_WAIT_QUEUE_HEAD(work_waitq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq); set_user_nice(current, -20); phba->work_wait = &work_waitq; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 24a1779b9af..582f5ea4e84 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2983,7 +2983,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, struct lpfc_iocbq * prspiocbq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD(done_q); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); long timeleft, timeout_req = 0; int retval = IOCB_SUCCESS; uint32_t creg_val; @@ -3061,7 +3061,7 @@ int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD(done_q); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); DECLARE_WAITQUEUE(wq_entry, current); uint32_t timeleft = 0; int retval; diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c0edb662d86..7bac86dda88 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -884,7 +884,7 @@ megaraid_init_mbox(adapter_t *adapter) if (((magic64 == HBA_SIGNATURE_64_BIT) && ((adapter->pdev->subsystem_device != - PCI_SUBSYS_ID_MEGARAID_SATA_150_6) || + 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 && diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index b1d34604952..f2d79c3f0b8 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -183,7 +183,7 @@ static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ... * Clenaup parameters and call done() functions. * You must be set SCpnt->result before call this function. */ -static void nsp_scsi_done(Scsi_Cmnd *SCpnt) +static void nsp_scsi_done(struct scsi_cmnd *SCpnt) { nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; @@ -192,7 +192,8 @@ static void nsp_scsi_done(Scsi_Cmnd *SCpnt) SCpnt->scsi_done(SCpnt); } -static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +static int nsp_queuecommand(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { #ifdef NSP_DEBUG /*unsigned int host_id = SCpnt->device->host->this_id;*/ @@ -365,7 +366,7 @@ static int nsphw_init(nsp_hw_data *data) /* * Start selection phase */ -static int nsphw_start_selection(Scsi_Cmnd *SCpnt) +static int nsphw_start_selection(struct scsi_cmnd *SCpnt) { unsigned int host_id = SCpnt->device->host->this_id; unsigned int base = SCpnt->device->host->io_port; @@ -446,7 +447,7 @@ static struct nsp_sync_table nsp_sync_table_20M[] = { /* * setup synchronous data transfer mode */ -static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt) +static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt) { unsigned char target = scmd_id(SCpnt); // unsigned char lun = SCpnt->device->lun; @@ -504,7 +505,7 @@ static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt) /* * start ninja hardware timer */ -static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time) +static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time) { unsigned int base = SCpnt->device->host->io_port; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; @@ -517,7 +518,8 @@ static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time) /* * wait for bus phase change */ -static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) +static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask, + char *str) { unsigned int base = SCpnt->device->host->io_port; unsigned char reg; @@ -544,9 +546,9 @@ static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) /* * expect Ninja Irq */ -static int nsp_expect_signal(Scsi_Cmnd *SCpnt, - unsigned char current_phase, - unsigned char mask) +static int nsp_expect_signal(struct scsi_cmnd *SCpnt, + unsigned char current_phase, + unsigned char mask) { unsigned int base = SCpnt->device->host->io_port; int time_out; @@ -579,7 +581,7 @@ static int nsp_expect_signal(Scsi_Cmnd *SCpnt, /* * transfer SCSI message */ -static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) +static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase) { unsigned int base = SCpnt->device->host->io_port; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; @@ -619,7 +621,7 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) /* * get extra SCSI data from fifo */ -static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) +static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt) { nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; unsigned int count; @@ -651,7 +653,7 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) /* * accept reselection */ -static int nsp_reselected(Scsi_Cmnd *SCpnt) +static int nsp_reselected(struct scsi_cmnd *SCpnt) { unsigned int base = SCpnt->device->host->io_port; unsigned int host_id = SCpnt->device->host->this_id; @@ -690,7 +692,7 @@ static int nsp_reselected(Scsi_Cmnd *SCpnt) /* * count how many data transferd */ -static int nsp_fifo_count(Scsi_Cmnd *SCpnt) +static int nsp_fifo_count(struct scsi_cmnd *SCpnt) { unsigned int base = SCpnt->device->host->io_port; unsigned int count; @@ -717,7 +719,7 @@ static int nsp_fifo_count(Scsi_Cmnd *SCpnt) /* * read data in DATA IN phase */ -static void nsp_pio_read(Scsi_Cmnd *SCpnt) +static void nsp_pio_read(struct scsi_cmnd *SCpnt) { unsigned int base = SCpnt->device->host->io_port; unsigned long mmio_base = SCpnt->device->host->base; @@ -812,7 +814,7 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt) /* * write data in DATA OUT phase */ -static void nsp_pio_write(Scsi_Cmnd *SCpnt) +static void nsp_pio_write(struct scsi_cmnd *SCpnt) { unsigned int base = SCpnt->device->host->io_port; unsigned long mmio_base = SCpnt->device->host->base; @@ -905,7 +907,7 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt) /* * setup synchronous/asynchronous data transfer mode */ -static int nsp_nexus(Scsi_Cmnd *SCpnt) +static int nsp_nexus(struct scsi_cmnd *SCpnt) { unsigned int base = SCpnt->device->host->io_port; unsigned char target = scmd_id(SCpnt); @@ -952,7 +954,7 @@ static irqreturn_t nspintr(int irq, void *dev_id) { unsigned int base; unsigned char irq_status, irq_phase, phase; - Scsi_Cmnd *tmpSC; + struct scsi_cmnd *tmpSC; unsigned char target, lun; unsigned int *sync_neg; int i, tmp; @@ -1530,7 +1532,7 @@ nsp_proc_info( /*---------------------------------------------------------------*/ /* -static int nsp_eh_abort(Scsi_Cmnd *SCpnt) +static int nsp_eh_abort(struct scsi_cmnd *SCpnt) { nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); @@ -1558,7 +1560,7 @@ static int nsp_bus_reset(nsp_hw_data *data) return SUCCESS; } -static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt) { nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; @@ -1567,7 +1569,7 @@ static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) return nsp_bus_reset(data); } -static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) +static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt) { nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index a88714f4c05..625ca97da52 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -266,7 +266,7 @@ typedef struct _nsp_hw_data { int TimerCount; int SelectionTimeOut; - Scsi_Cmnd *CurrentSC; + struct scsi_cmnd *CurrentSC; //int CurrnetTarget; int FifoCount; @@ -319,30 +319,34 @@ static int nsp_proc_info ( int hostno, #endif int inout); -static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *SCpnt)); +static int nsp_queuecommand(struct scsi_cmnd *SCpnt, + void (* done)(struct scsi_cmnd *SCpnt)); /* Error handler */ -/*static int nsp_eh_abort (Scsi_Cmnd *SCpnt);*/ -/*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/ -static int nsp_eh_bus_reset (Scsi_Cmnd *SCpnt); -static int nsp_eh_host_reset (Scsi_Cmnd *SCpnt); +/*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/ +/*static int nsp_eh_device_reset(struct scsi_cmnd *SCpnt);*/ +static int nsp_eh_bus_reset (struct scsi_cmnd *SCpnt); +static int nsp_eh_host_reset (struct scsi_cmnd *SCpnt); static int nsp_bus_reset (nsp_hw_data *data); /* */ static int nsphw_init (nsp_hw_data *data); -static int nsphw_start_selection(Scsi_Cmnd *SCpnt); -static void nsp_start_timer (Scsi_Cmnd *SCpnt, int time); -static int nsp_fifo_count (Scsi_Cmnd *SCpnt); -static void nsp_pio_read (Scsi_Cmnd *SCpnt); -static void nsp_pio_write (Scsi_Cmnd *SCpnt); -static int nsp_nexus (Scsi_Cmnd *SCpnt); -static void nsp_scsi_done (Scsi_Cmnd *SCpnt); -static int nsp_analyze_sdtr (Scsi_Cmnd *SCpnt); -static int nsp_negate_signal (Scsi_Cmnd *SCpnt, unsigned char mask, char *str); -static int nsp_expect_signal (Scsi_Cmnd *SCpnt, unsigned char current_phase, unsigned char mask); -static int nsp_xfer (Scsi_Cmnd *SCpnt, int phase); -static int nsp_dataphase_bypass (Scsi_Cmnd *SCpnt); -static int nsp_reselected (Scsi_Cmnd *SCpnt); +static int nsphw_start_selection(struct scsi_cmnd *SCpnt); +static void nsp_start_timer (struct scsi_cmnd *SCpnt, int time); +static int nsp_fifo_count (struct scsi_cmnd *SCpnt); +static void nsp_pio_read (struct scsi_cmnd *SCpnt); +static void nsp_pio_write (struct scsi_cmnd *SCpnt); +static int nsp_nexus (struct scsi_cmnd *SCpnt); +static void nsp_scsi_done (struct scsi_cmnd *SCpnt); +static int nsp_analyze_sdtr (struct scsi_cmnd *SCpnt); +static int nsp_negate_signal (struct scsi_cmnd *SCpnt, + unsigned char mask, char *str); +static int nsp_expect_signal (struct scsi_cmnd *SCpnt, + unsigned char current_phase, + unsigned char mask); +static int nsp_xfer (struct scsi_cmnd *SCpnt, int phase); +static int nsp_dataphase_bypass (struct scsi_cmnd *SCpnt); +static int nsp_reselected (struct scsi_cmnd *SCpnt); static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht); /* Interrupt handler */ @@ -355,8 +359,8 @@ static void __exit nsp_cs_exit(void); /* Debug */ #ifdef NSP_DEBUG -static void show_command (Scsi_Cmnd *SCpnt); -static void show_phase (Scsi_Cmnd *SCpnt); +static void show_command (struct scsi_cmnd *SCpnt); +static void show_phase (struct scsi_cmnd *SCpnt); static void show_busphase(unsigned char stat); static void show_message (nsp_hw_data *data); #else diff --git a/drivers/scsi/pcmcia/nsp_debug.c b/drivers/scsi/pcmcia/nsp_debug.c index 62e5c60067f..2f75fe6e35a 100644 --- a/drivers/scsi/pcmcia/nsp_debug.c +++ b/drivers/scsi/pcmcia/nsp_debug.c @@ -138,12 +138,12 @@ static void print_commandk (unsigned char *command) printk("\n"); } -static void show_command(Scsi_Cmnd *SCpnt) +static void show_command(struct scsi_cmnd *SCpnt) { print_commandk(SCpnt->cmnd); } -static void show_phase(Scsi_Cmnd *SCpnt) +static void show_phase(struct scsi_cmnd *SCpnt) { int i = SCpnt->SCp.phase; diff --git a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c index d7057737ff3..ef593b70d0f 100644 --- a/drivers/scsi/pcmcia/nsp_message.c +++ b/drivers/scsi/pcmcia/nsp_message.c @@ -8,7 +8,7 @@ /* $Id: nsp_message.c,v 1.6 2003/07/26 14:21:09 elca Exp $ */ -static void nsp_message_in(Scsi_Cmnd *SCpnt) +static void nsp_message_in(struct scsi_cmnd *SCpnt) { unsigned int base = SCpnt->device->host->io_port; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; @@ -50,7 +50,7 @@ static void nsp_message_in(Scsi_Cmnd *SCpnt) } -static void nsp_message_out(Scsi_Cmnd *SCpnt) +static void nsp_message_out(struct scsi_cmnd *SCpnt) { nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; int ret = 1; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index b0eba39f208..89a2a9f11e4 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -1012,7 +1012,7 @@ static LIST_HEAD(ppa_hosts); static int __ppa_attach(struct parport *pb) { struct Scsi_Host *host; - DECLARE_WAIT_QUEUE_HEAD(waiting); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); ppa_struct *dev; int ports; diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c index a720c9265e6..899e89d6fe6 100644 --- a/drivers/scsi/psi240i.c +++ b/drivers/scsi/psi240i.c @@ -87,11 +87,11 @@ typedef struct { USHORT ports[13]; OUR_DEVICE device[8]; - Scsi_Cmnd *pSCmnd; + struct scsi_cmnd *pSCmnd; IDE_STRUCT ide; ULONG startSector; USHORT sectorCount; - Scsi_Cmnd *SCpnt; + struct scsi_cmnd *SCpnt; VOID *buffer; USHORT expectingIRQ; } ADAPTER240I, *PADAPTER240I; @@ -253,12 +253,12 @@ static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status) ****************************************************************/ static void Irq_Handler (int irq, void *dev_id) { - struct Scsi_Host *shost; // Pointer to host data block - PADAPTER240I padapter; // Pointer to adapter control structure - USHORT *pports; // I/O port array - Scsi_Cmnd *SCpnt; - UCHAR status; - int z; + struct Scsi_Host *shost; // Pointer to host data block + PADAPTER240I padapter; // Pointer to adapter control structure + USHORT *pports; // I/O port array + struct scsi_cmnd *SCpnt; + UCHAR status; + int z; DEB(printk ("\npsi240i received interrupt\n")); @@ -328,7 +328,7 @@ static void Irq_Handler (int irq, void *dev_id) pinquiryData->AdditionalLength = 35 - 4; // Fill in vendor identification fields. - for ( z = 0; z < 20; z += 2 ) + for ( z = 0; z < 8; z += 2 ) { pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1]; pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z]; @@ -389,12 +389,17 @@ static irqreturn_t do_Irq_Handler (int irq, void *dev_id) * Returns: Status code. * ****************************************************************/ -static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { - UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB - PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); // Pointer to adapter control structure - POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];// Pointer to device information - UCHAR rc; // command return code + UCHAR *cdb = (UCHAR *)SCpnt->cmnd; + // Pointer to SCSI CDB + PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); + // Pointer to adapter control structure + POUR_DEVICE pdev = &padapter->device [SCpnt->device->id]; + // Pointer to device information + UCHAR rc; + // command return code SCpnt->scsi_done = done; padapter->ide.ide.ides.spigot = pdev->spigot; diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h index 6a598766df5..21ebb921400 100644 --- a/drivers/scsi/psi240i.h +++ b/drivers/scsi/psi240i.h @@ -309,7 +309,7 @@ typedef struct _IDENTIFY_DATA2 { #endif // PSI_EIDE_SCSIOP // function prototypes -int Psi240i_Command (Scsi_Cmnd *SCpnt); -int Psi240i_Abort (Scsi_Cmnd *SCpnt); -int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); +int Psi240i_Command(struct scsi_cmnd *SCpnt); +int Psi240i_Abort(struct scsi_cmnd *SCpnt); +int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags); #endif diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 2521d548dd5..16af5b79e58 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -931,11 +931,10 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) case BUS_RESET: if (qla1280_verbose) - printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS " - "DEVICE RESET\n", ha->host_no, bus); - if (qla1280_bus_reset(ha, bus == 0)) + printk(KERN_INFO "qla1280(%ld:%d): Issued bus " + "reset.\n", ha->host_no, bus); + if (qla1280_bus_reset(ha, bus) == 0) result = SUCCESS; - break; case ADAPTER_RESET: diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index ee75a71f3c6..285c8e8ff1a 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -379,21 +379,37 @@ static struct bin_attribute sysfs_sfp_attr = { .read = qla2x00_sysfs_read_sfp, }; +static struct sysfs_entry { + char *name; + struct bin_attribute *attr; + int is4GBp_only; +} bin_file_entries[] = { + { "fw_dump", &sysfs_fw_dump_attr, }, + { "nvram", &sysfs_nvram_attr, }, + { "optrom", &sysfs_optrom_attr, }, + { "optrom_ctl", &sysfs_optrom_ctl_attr, }, + { "vpd", &sysfs_vpd_attr, 1 }, + { "sfp", &sysfs_sfp_attr, 1 }, + { 0 }, +}; + void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) { struct Scsi_Host *host = ha->host; + struct sysfs_entry *iter; + int ret; - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, - &sysfs_optrom_ctl_attr); - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - sysfs_create_bin_file(&host->shost_gendev.kobj, - &sysfs_vpd_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, - &sysfs_sfp_attr); + for (iter = bin_file_entries; iter->name; iter++) { + if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))) + continue; + + ret = sysfs_create_bin_file(&host->shost_gendev.kobj, + iter->attr); + if (ret) + qla_printk(KERN_INFO, ha, + "Unable to create sysfs %s binary attribute " + "(%d).\n", iter->name, ret); } } @@ -401,17 +417,14 @@ void qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) { struct Scsi_Host *host = ha->host; + struct sysfs_entry *iter; + + for (iter = bin_file_entries; iter->name; iter++) { + if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))) + continue; - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, - &sysfs_optrom_ctl_attr); - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - sysfs_remove_bin_file(&host->shost_gendev.kobj, - &sysfs_vpd_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, - &sysfs_sfp_attr); + iter->attr); } if (ha->beacon_blink_led == 1) diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 90dad7e8898..5b12278968e 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -38,7 +38,7 @@ * Macros use for debugging the driver. */ -#define DEBUG(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_1) #define DEBUG1(x) do {x;} while (0) @@ -46,12 +46,12 @@ #define DEBUG1(x) do {} while (0) #endif -#define DEBUG2(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_3(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_3_11(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_9_10(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_11(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_13(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_3(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_3_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index bab33f6d0bd..c4fc40f8e8c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1545,6 +1545,9 @@ typedef struct fc_port { spinlock_t rport_lock; struct fc_rport *rport, *drport; u32 supported_classes; + + unsigned long last_queue_full; + unsigned long last_ramp_up; } fc_port_t; /* @@ -2255,6 +2258,7 @@ typedef struct scsi_qla_host { uint16_t mgmt_svr_loop_id; uint32_t login_retry_count; + int max_q_depth; /* Fibre Channel Device List. */ struct list_head fcports; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 7da69832d74..32ebeec45ff 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -48,6 +48,7 @@ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); +extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); /* * Global Data in qla_os.c source file. @@ -60,7 +61,8 @@ extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; extern int ql2xallocfwdump; -extern int qla2_extended_error_logging; +extern int ql2xextended_error_logging; +extern int ql2xqfullrampup; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 833b93085fd..08cb5e3fb55 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1644,7 +1644,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) * Set host adapter parameters. */ if (nv->host_p[0] & BIT_7) - qla2_extended_error_logging = 1; + ql2xextended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) @@ -3948,3 +3948,24 @@ qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr) fail_fw_integrity: return QLA_FUNCTION_FAILED; } + +void +qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha) +{ + int ret, retries; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return; + + ret = qla2x00_stop_firmware(ha); + for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) { + qla2x00_reset_chip(ha); + if (qla2x00_chip_diag(ha) != QLA_SUCCESS) + continue; + if (qla2x00_setup_chip(ha) != QLA_SUCCESS) + continue; + qla_printk(KERN_INFO, ha, + "Attempting retry of stop-firmware command...\n"); + ret = qla2x00_stop_firmware(ha); + } +} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 626c7178a43..d3b6df4d55c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -6,6 +6,8 @@ */ #include "qla_def.h" +#include <scsi/scsi_tcq.h> + static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *); static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t); @@ -593,6 +595,67 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) } } +static void +qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data) +{ + fc_port_t *fcport = data; + + if (fcport->ha->max_q_depth <= sdev->queue_depth) + return; + + if (sdev->ordered_tags) + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, + sdev->queue_depth + 1); + else + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, + sdev->queue_depth + 1); + + fcport->last_ramp_up = jiffies; + + DEBUG2(qla_printk(KERN_INFO, fcport->ha, + "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n", + fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun, + sdev->queue_depth)); +} + +static void +qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data) +{ + fc_port_t *fcport = data; + + if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1)) + return; + + DEBUG2(qla_printk(KERN_INFO, fcport->ha, + "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n", + fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun, + sdev->queue_depth)); +} + +static inline void +qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp) +{ + fc_port_t *fcport; + struct scsi_device *sdev; + + sdev = sp->cmd->device; + if (sdev->queue_depth >= ha->max_q_depth) + return; + + fcport = sp->fcport; + if (time_before(jiffies, + fcport->last_ramp_up + ql2xqfullrampup * HZ)) + return; + if (time_before(jiffies, + fcport->last_queue_full + ql2xqfullrampup * HZ)) + return; + + spin_unlock_irq(&ha->hardware_lock); + starget_for_each_device(sdev->sdev_target, fcport, + qla2x00_adjust_sdev_qdepth_up); + spin_lock_irq(&ha->hardware_lock); +} + /** * qla2x00_process_completed_request() - Process a Fast Post response. * @ha: SCSI driver HA context @@ -624,6 +687,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index) /* Save ISP completion status */ sp->cmd->result = DID_OK << 16; + + qla2x00_ramp_up_queue_depth(ha, sp); qla2x00_sp_compl(ha, sp); } else { DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n", @@ -823,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) */ switch (comp_status) { case CS_COMPLETE: + case CS_QUEUE_FULL: if (scsi_status == 0) { cp->result = DID_OK << 16; break; @@ -849,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) } cp->result = DID_OK << 16 | lscsi_status; + if (lscsi_status == SAM_STAT_TASK_SET_FULL) { + DEBUG2(printk(KERN_INFO + "scsi(%ld): QUEUE FULL status detected " + "0x%x-0x%x.\n", ha->host_no, comp_status, + scsi_status)); + + /* Adjust queue depth for all luns on the port. */ + fcport->last_queue_full = jiffies; + spin_unlock_irq(&ha->hardware_lock); + starget_for_each_device(cp->device->sdev_target, + fcport, qla2x00_adjust_sdev_qdepth_down); + spin_lock_irq(&ha->hardware_lock); + break; + } if (lscsi_status != SS_CHECK_CONDITION) break; @@ -1066,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) qla2x00_mark_device_lost(ha, fcport, 1, 1); break; - case CS_QUEUE_FULL: - DEBUG2(printk(KERN_INFO - "scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n", - ha->host_no, comp_status, scsi_status)); - - /* SCSI Mid-Layer handles device queue full */ - - cp->result = DID_OK << 16 | lscsi_status; - - break; - default: DEBUG3(printk("scsi(%ld): Error detected (unknown status) " "0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status)); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5e70c49fdf8..3eb4cd2cbc7 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -61,9 +61,9 @@ MODULE_PARM_DESC(ql2xallocfwdump, "during HBA initialization. Memory allocation requirements " "vary by ISP type. Default is 1 - allocate memory."); -int qla2_extended_error_logging; -module_param(qla2_extended_error_logging, int, S_IRUGO|S_IRUSR); -MODULE_PARM_DESC(qla2_extended_error_logging, +int ql2xextended_error_logging; +module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging. 1 - log errors."); @@ -77,6 +77,19 @@ MODULE_PARM_DESC(ql2xfdmienable, "Enables FDMI registratons " "Default is 0 - no FDMI. 1 - perfom FDMI."); +#define MAX_Q_DEPTH 32 +static int ql2xmaxqdepth = MAX_Q_DEPTH; +module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xmaxqdepth, + "Maximum queue depth to report for target devices."); + +int ql2xqfullrampup = 120; +module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xqfullrampup, + "Number of seconds to wait to begin to ramp-up the queue " + "depth for a device after a queue-full condition has been " + "detected. Default is 120 seconds."); + /* * SCSI host template entry points */ @@ -1104,9 +1117,9 @@ qla2xxx_slave_configure(struct scsi_device *sdev) struct fc_rport *rport = starget_to_rport(sdev->sdev_target); if (sdev->tagged_supported) - scsi_activate_tcq(sdev, 32); + scsi_activate_tcq(sdev, ha->max_q_depth); else - scsi_deactivate_tcq(sdev, 32); + scsi_deactivate_tcq(sdev, ha->max_q_depth); rport->dev_loss_tmo = ha->port_down_retry_count + 5; @@ -1413,6 +1426,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->link_data_rate = PORT_SPEED_UNKNOWN; ha->optrom_size = OPTROM_SIZE_2300; + ha->max_q_depth = MAX_Q_DEPTH; + if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU) + ha->max_q_depth = ql2xmaxqdepth; + /* Assign ISP specific operations. */ ha->isp_ops.pci_config = qla2100_pci_config; ha->isp_ops.reset_chip = qla2x00_reset_chip; @@ -1712,8 +1729,10 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (ha->eft) qla2x00_trace_control(ha, TC_DISABLE, 0, 0); + ha->flags.online = 0; + /* Stop currently executing firmware. */ - qla2x00_stop_firmware(ha); + qla2x00_try_to_stop_firmware(ha); /* turn-off interrupts on the card */ if (ha->interrupts_on) @@ -1721,8 +1740,6 @@ qla2x00_free_device(scsi_qla_host_t *ha) qla2x00_mem_free(ha); - ha->flags.online = 0; - /* Detach interrupts */ if (ha->host->irq) free_irq(ha->host->irq, ha); @@ -2697,7 +2714,7 @@ qla2x00_module_init(void) /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); - if (qla2_extended_error_logging) + if (ql2xextended_error_logging) strcat(qla2x00_version_str, "-debug"); qla2xxx_transport_template = diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e57bf45a339..1fa0bce6b24 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.07-k2" +#define QLA2XXX_VERSION "8.01.07-k3" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig index 08a07f0b8d9..69cbff3f57c 100644 --- a/drivers/scsi/qla4xxx/Kconfig +++ b/drivers/scsi/qla4xxx/Kconfig @@ -1,6 +1,6 @@ config SCSI_QLA_ISCSI tristate "QLogic ISP4XXX host adapter family support" - depends on PCI && SCSI + depends on PCI && SCSI && NET select SCSI_ISCSI_ATTRS ---help--- This driver supports the QLogic 40xx (ISP4XXX) iSCSI host diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h index 3e99dcfd5a9..d861c3b411c 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.h +++ b/drivers/scsi/qla4xxx/ql4_dbg.h @@ -22,14 +22,14 @@ #endif #if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {if(qla4_extended_error_logging == 2) x;} while (0); +#define DEBUG2(x) do {if(ql4xextended_error_logging == 2) x;} while (0); #define DEBUG2_3(x) do {x;} while (0); #else /* */ #define DEBUG2(x) do {} while (0); #endif /* */ #if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {if(qla4_extended_error_logging == 3) x;} while (0); +#define DEBUG3(x) do {if(ql4xextended_error_logging == 3) x;} while (0); #else /* */ #define DEBUG3(x) do {} while (0); #if !defined(QL_DEBUG_LEVEL_2) diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 2c803edf2de..eeefdcb1edb 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -8,6 +8,7 @@ #ifndef __QLA4x_GBL_H #define __QLA4x_GBL_H +int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb); int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, @@ -72,7 +73,7 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, uint32_t fw_ddb_index, uint32_t state); -extern int qla4_extended_error_logging; +extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; extern int ql4xdontresethba; #endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index bb3a1c11f44..9e81b810dc8 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -978,7 +978,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) return status; } -static int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) +int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) { #define QL4_LOCK_DRVR_WAIT 300 #define QL4_LOCK_DRVR_SLEEP 100 diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index ef82399c085..b721dc5dd71 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -701,7 +701,7 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", ha->host_no, num_valid_entries)); - if (qla4_extended_error_logging == 3) { + if (ql4xextended_error_logging == 3) { if (oldest_entry == 0) { /* Circular Buffer has not wrapped around */ for (i=0; i < num_valid_entries; i++) { diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 178fcddcfd8..bab434ee774 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -34,9 +34,9 @@ MODULE_PARM_DESC(ql4xdontresethba, " default it will reset hba :0" " set to 1 to avoid resetting HBA"); -int qla4_extended_error_logging = 0; /* 0 = off, 1 = log errors */ -module_param(qla4_extended_error_logging, int, S_IRUGO | S_IRUSR); -MODULE_PARM_DESC(qla4_extended_error_logging, +int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ +module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(ql4xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging, 1 - debug logging"); @@ -919,18 +919,11 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, if (status == QLA_SUCCESS) { DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n", ha->host_no, __func__)); - status = qla4xxx_soft_reset(ha); - } - /* FIXMEkaren: Do we want to keep interrupts enabled and process - AENs after soft reset */ - - /* If firmware (SOFT) reset failed, or if all outstanding - * commands have not returned, then do a HARD reset. - */ - if (status == QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n", - ha->host_no, __func__)); - status = qla4xxx_hard_reset(ha); + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) + status = qla4xxx_soft_reset(ha); + else + status = QLA_ERROR; } /* Flush any pending ddb changed AENs */ @@ -1016,13 +1009,9 @@ static void qla4xxx_do_dpc(void *data) struct scsi_qla_host *ha = (struct scsi_qla_host *) data; struct ddb_entry *ddb_entry, *dtemp; - DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n", - ha->host_no, __func__)); - - DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n", - ha->host_no, __func__, ha->flags)); - DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n", - ha->host_no, __func__, ha->dpc_flags)); + DEBUG2(printk("scsi%ld: %s: DPC handler waking up." + "flags = 0x%08lx, dpc_flags = 0x%08lx\n", + ha->host_no, __func__, ha->flags, ha->dpc_flags)); /* Initialization not yet finished. Don't do anything yet. */ if (!test_bit(AF_INIT_DONE, &ha->flags)) @@ -1032,16 +1021,8 @@ static void qla4xxx_do_dpc(void *data) test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { - if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) - /* - * dg 09/23 Never initialize ddb list - * once we up and running - * qla4xxx_recover_adapter(ha, - * REBUILD_DDB_LIST); - */ - qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); - - if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) + if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || + test_bit(DPC_RESET_HA, &ha->dpc_flags)) qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { @@ -1122,7 +1103,8 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) destroy_workqueue(ha->dpc_thread); /* Issue Soft Reset to put firmware in unknown state */ - qla4xxx_soft_reset(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) + qla4xxx_soft_reset(ha); /* Remove timer thread, if present */ if (ha->timer_active) @@ -1714,7 +1696,7 @@ static int __init qla4xxx_module_init(void) /* Derive version string. */ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); - if (qla4_extended_error_logging) + if (ql4xextended_error_logging) strcat(qla4xxx_version_str, "-debug"); qla4xxx_scsi_transport = @@ -1724,13 +1706,13 @@ static int __init qla4xxx_module_init(void) goto release_srb_cache; } - printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); ret = pci_register_driver(&qla4xxx_pci_driver); if (ret) goto unregister_transport; printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); return 0; + unregister_transport: iscsi_unregister_transport(&qla4xxx_iscsi_transport); release_srb_cache: diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index b3fe7e68988..d05048b4e88 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,9 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k" - -#define QL4_DRIVER_MAJOR_VER 5 -#define QL4_DRIVER_MINOR_VER 0 -#define QL4_DRIVER_PATCH_VER 5 -#define QL4_DRIVER_BETA_VER 9 +#define QLA4XXX_DRIVER_VERSION "5.00.06-k" diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index e0725353c99..2e7db18f5ae 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -209,7 +209,7 @@ static int ql_wai(struct qlogicfas408_priv *priv) * caller must hold host lock */ -static void ql_icmd(Scsi_Cmnd * cmd) +static void ql_icmd(struct scsi_cmnd *cmd) { struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); int qbase = priv->qbase; @@ -256,7 +256,7 @@ static void ql_icmd(Scsi_Cmnd * cmd) * Process scsi command - usually after interrupt */ -static unsigned int ql_pcmd(Scsi_Cmnd * cmd) +static unsigned int ql_pcmd(struct scsi_cmnd *cmd) { unsigned int i, j; unsigned long k; @@ -407,7 +407,7 @@ static unsigned int ql_pcmd(Scsi_Cmnd * cmd) static void ql_ihandl(void *dev_id) { - Scsi_Cmnd *icmd; + struct scsi_cmnd *icmd; struct Scsi_Host *host = dev_id; struct qlogicfas408_priv *priv = get_priv_by_host(host); int qbase = priv->qbase; @@ -447,7 +447,8 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) * Queued command */ -int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +int qlogicfas408_queuecommand(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)) { struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); if (scmd_id(cmd) == priv->qinitid) { @@ -470,9 +471,8 @@ int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) * Return bios parameters */ -int qlogicfas408_biosparam(struct scsi_device * disk, - struct block_device *dev, - sector_t capacity, int ip[]) +int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev, + sector_t capacity, int ip[]) { /* This should mimic the DOS Qlogic driver's behavior exactly */ ip[0] = 0x40; @@ -494,7 +494,7 @@ int qlogicfas408_biosparam(struct scsi_device * disk, * Abort a command in progress */ -int qlogicfas408_abort(Scsi_Cmnd * cmd) +int qlogicfas408_abort(struct scsi_cmnd *cmd) { struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); priv->qabort = 1; @@ -508,7 +508,7 @@ int qlogicfas408_abort(Scsi_Cmnd * cmd) * the PCMCIA qlogic_stub code. This wants fixing */ -int qlogicfas408_bus_reset(Scsi_Cmnd * cmd) +int qlogicfas408_bus_reset(struct scsi_cmnd *cmd) { struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); unsigned long flags; diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h index 8fd5555c75b..260626427a3 100644 --- a/drivers/scsi/qlogicfas408.h +++ b/drivers/scsi/qlogicfas408.h @@ -75,15 +75,15 @@ /*----------------------------------------------------------------*/ struct qlogicfas408_priv { - int qbase; /* Port */ - int qinitid; /* initiator ID */ - int qabort; /* Flag to cause an abort */ - int qlirq; /* IRQ being used */ - int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */ - char qinfo[80]; /* description */ - Scsi_Cmnd *qlcmd; /* current command being processed */ - struct Scsi_Host *shost; /* pointer back to host */ - struct qlogicfas408_priv *next; /* next private struct */ + int qbase; /* Port */ + int qinitid; /* initiator ID */ + int qabort; /* Flag to cause an abort */ + int qlirq; /* IRQ being used */ + int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */ + char qinfo[80]; /* description */ + struct scsi_cmnd *qlcmd; /* current command being processed */ + struct Scsi_Host *shost; /* pointer back to host */ + struct qlogicfas408_priv *next; /* next private struct */ }; /* The qlogic card uses two register maps - These macros select which one */ @@ -103,12 +103,13 @@ struct qlogicfas408_priv { #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); -int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); +int qlogicfas408_queuecommand(struct scsi_cmnd * cmd, + void (*done) (struct scsi_cmnd *)); int qlogicfas408_biosparam(struct scsi_device * disk, - struct block_device *dev, - sector_t capacity, int ip[]); -int qlogicfas408_abort(Scsi_Cmnd * cmd); -int qlogicfas408_bus_reset(Scsi_Cmnd * cmd); + struct block_device *dev, + sector_t capacity, int ip[]); +int qlogicfas408_abort(struct scsi_cmnd * cmd); +int qlogicfas408_bus_reset(struct scsi_cmnd * cmd); const char *qlogicfas408_info(struct Scsi_Host *host); int qlogicfas408_get_chip_type(int qbase, int int_type); void qlogicfas408_setup(int qbase, int id, int int_type); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index ed58bb48988..9b827ceec50 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host) #define PTI_RESET_LIMIT 400 -static int __init qlogicpti_load_firmware(struct qlogicpti *qpti) +static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) { struct Scsi_Host *host = qpti->qhost; unsigned short csum = 0; diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c index 1545b30681b..19aa84f4601 100644 --- a/drivers/scsi/qlogicpti_asm.c +++ b/drivers/scsi/qlogicpti_asm.c @@ -1,5 +1,5 @@ /* Version 1.31.00 ISP1000 Initiator RISC firmware */ -unsigned short sbus_risc_code01[] __initdata = { +unsigned short sbus_risc_code01[] __devinitdata = { 0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, @@ -1157,4 +1157,4 @@ unsigned short sbus_risc_code01[] __initdata = { 0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c, 0x92a7 }; -unsigned short sbus_risc_code_length01 = 0x2419; +unsigned short __devinitdata sbus_risc_code_length01 = 0x2419; diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 9c0f35820e3..30ee3d72c02 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -52,7 +52,7 @@ #include "scsi_debug.h" #define SCSI_DEBUG_VERSION "1.80" -static const char * scsi_debug_version_date = "20060914"; +static const char * scsi_debug_version_date = "20061018"; /* Additional Sense Code (ASC) used */ #define NO_ADDITIONAL_SENSE 0x0 @@ -254,6 +254,8 @@ static int resp_requests(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int resp_start_stop(struct scsi_cmnd * scp, struct sdebug_dev_info * devip); +static int resp_report_tgtpgs(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip); static int resp_readcap(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int resp_readcap16(struct scsi_cmnd * SCpnt, @@ -287,9 +289,9 @@ static void __init sdebug_build_parts(unsigned char * ramp); static void __init init_all_queued(void); static void stop_all_queued(void); static int stop_queued_cmnd(struct scsi_cmnd * cmnd); -static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, - int dev_id_num, const char * dev_id_str, - int dev_id_str_len); +static int inquiry_evpd_83(unsigned char * arr, int port_group_id, + int target_dev_id, int dev_id_num, + const char * dev_id_str, int dev_id_str_len); static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); static int do_create_driverfs_files(void); static void do_remove_driverfs_files(void); @@ -422,6 +424,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) } errsts = resp_readcap16(SCpnt, devip); break; + case MAINTENANCE_IN: + if (MI_REPORT_TARGET_PGS != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + errsts = resp_report_tgtpgs(SCpnt, devip); + break; case READ_16: case READ_12: case READ_10: @@ -665,8 +676,9 @@ static const char * inq_vendor_id = "Linux "; static const char * inq_product_id = "scsi_debug "; static const char * inq_product_rev = "0004"; -static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, - int dev_id_num, const char * dev_id_str, +static int inquiry_evpd_83(unsigned char * arr, int port_group_id, + int target_dev_id, int dev_id_num, + const char * dev_id_str, int dev_id_str_len) { int num, port_a; @@ -720,6 +732,15 @@ static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, arr[num++] = (port_a >> 16) & 0xff; arr[num++] = (port_a >> 8) & 0xff; arr[num++] = port_a & 0xff; + /* NAA-5, Target port group identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x95; /* piv=1, target port group id */ + arr[num++] = 0x0; + arr[num++] = 0x4; + arr[num++] = 0; + arr[num++] = 0; + arr[num++] = (port_group_id >> 8) & 0xff; + arr[num++] = port_group_id & 0xff; /* NAA-5, Target device identifier */ arr[num++] = 0x61; /* proto=sas, binary */ arr[num++] = 0xa3; /* piv=1, target device, naa */ @@ -928,12 +949,12 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) { unsigned char pq_pdt; - unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; + unsigned char * arr; unsigned char *cmd = (unsigned char *)scp->cmnd; - int alloc_len, n; + int alloc_len, n, ret; alloc_len = (cmd[3] << 8) + cmd[4]; - memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); + arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL); if (devip->wlun) pq_pdt = 0x1e; /* present, wlun */ else if (scsi_debug_no_lun_0 && (0 == devip->lun)) @@ -944,12 +965,15 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + kfree(arr); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ - int lu_id_num, target_dev_id, len; + int lu_id_num, port_group_id, target_dev_id, len; char lu_id_str[6]; int host_no = devip->sdbg_host->shost->host_no; + port_group_id = (((host_no + 1) & 0x7f) << 8) + + (devip->channel & 0x7f); if (0 == scsi_debug_vpd_use_hostno) host_no = 0; lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + @@ -977,8 +1001,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, - lu_id_num, lu_id_str, len); + arr[3] = inquiry_evpd_83(&arr[4], port_group_id, + target_dev_id, lu_id_num, + lu_id_str, len); } else if (0x84 == cmd[2]) { /* Software interface ident. */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_evpd_84(&arr[4]); @@ -1012,17 +1037,22 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + kfree(arr); return check_condition_result; } len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); - return fill_from_dev_buffer(scp, arr, + ret = fill_from_dev_buffer(scp, arr, min(len, SDEBUG_MAX_INQ_ARR_SZ)); + kfree(arr); + return ret; } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[2] = scsi_debug_scsi_level; arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; + if (0 == scsi_debug_vpd_use_hostno) + arr[5] = 0x10; /* claim: implicit TGPS */ arr[6] = 0x10; /* claim: MultiP */ /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ arr[7] = 0xa; /* claim: LINKED + CMDQUE */ @@ -1039,8 +1069,10 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ } arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ - return fill_from_dev_buffer(scp, arr, + ret = fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_LONG_INQ_SZ)); + kfree(arr); + return ret; } static int resp_requests(struct scsi_cmnd * scp, @@ -1171,6 +1203,87 @@ static int resp_readcap16(struct scsi_cmnd * scp, min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); } +#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 + +static int resp_report_tgtpgs(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char * arr; + int host_no = devip->sdbg_host->shost->host_no; + int n, ret, alen, rlen; + int port_group_a, port_group_b, port_a, port_b; + + alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) + + cmd[9]); + + arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL); + /* + * EVPD page 0x88 states we have two ports, one + * real and a fake port with no device connected. + * So we create two port groups with one port each + * and set the group with port B to unavailable. + */ + port_a = 0x1; /* relative port A */ + port_b = 0x2; /* relative port B */ + port_group_a = (((host_no + 1) & 0x7f) << 8) + + (devip->channel & 0x7f); + port_group_b = (((host_no + 1) & 0x7f) << 8) + + (devip->channel & 0x7f) + 0x80; + + /* + * The asymmetric access state is cycled according to the host_id. + */ + n = 4; + if (0 == scsi_debug_vpd_use_hostno) { + arr[n++] = host_no % 3; /* Asymm access state */ + arr[n++] = 0x0F; /* claim: all states are supported */ + } else { + arr[n++] = 0x0; /* Active/Optimized path */ + arr[n++] = 0x01; /* claim: only support active/optimized paths */ + } + arr[n++] = (port_group_a >> 8) & 0xff; + arr[n++] = port_group_a & 0xff; + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Status code */ + arr[n++] = 0; /* Vendor unique */ + arr[n++] = 0x1; /* One port per group */ + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Reserved */ + arr[n++] = (port_a >> 8) & 0xff; + arr[n++] = port_a & 0xff; + arr[n++] = 3; /* Port unavailable */ + arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ + arr[n++] = (port_group_b >> 8) & 0xff; + arr[n++] = port_group_b & 0xff; + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Status code */ + arr[n++] = 0; /* Vendor unique */ + arr[n++] = 0x1; /* One port per group */ + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Reserved */ + arr[n++] = (port_b >> 8) & 0xff; + arr[n++] = port_b & 0xff; + + rlen = n - 4; + arr[0] = (rlen >> 24) & 0xff; + arr[1] = (rlen >> 16) & 0xff; + arr[2] = (rlen >> 8) & 0xff; + arr[3] = rlen & 0xff; + + /* + * Return the smallest value of either + * - The allocated length + * - The constructed command length + * - The maximum array size + */ + rlen = min(alen,n); + ret = fill_from_dev_buffer(scp, arr, + min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); + kfree(arr); + return ret; +} + /* <<Following mode page info copied from ST318451LW>> */ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ee35a62bb7a..2f12f9f12fc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -410,6 +410,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, goto free_req; req->cmd_len = cmd_len; + memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ memcpy(req->cmd, cmd, req->cmd_len); req->sense = sioc->sense; req->sense_len = 0; @@ -1119,7 +1120,7 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) req->buffer = NULL; } - BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd)); + BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd)); memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd)); cmd->cmd_len = req->cmd_len; if (!req->data_len) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 148e24cc322..aa1b1e0e9d2 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -700,12 +700,22 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, * scanning run at their own risk, or supply a user level program * that can correctly scan. */ - sdev->inquiry = kmalloc(sdev->inquiry_len, GFP_ATOMIC); - if (sdev->inquiry == NULL) { + + /* + * Copy at least 36 bytes of INQUIRY data, so that we don't + * dereference unallocated memory when accessing the Vendor, + * Product, and Revision strings. Badly behaved devices may set + * the INQUIRY Additional Length byte to a small value, indicating + * these strings are invalid, but often they contain plausible data + * nonetheless. It doesn't matter if the device sent < 36 bytes + * total, since scsi_probe_lun() initializes inq_result with 0s. + */ + sdev->inquiry = kmemdup(inq_result, + max_t(size_t, sdev->inquiry_len, 36), + GFP_ATOMIC); + if (sdev->inquiry == NULL) return SCSI_SCAN_NO_RESPONSE; - } - memcpy(sdev->inquiry, inq_result, sdev->inquiry_len); sdev->vendor = (char *) (sdev->inquiry + 8); sdev->model = (char *) (sdev->inquiry + 16); sdev->rev = (char *) (sdev->inquiry + 32); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e7fe565b96d..e1a91665d1c 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -192,6 +192,7 @@ static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost shost_rd_attr(unique_id, "%u\n"); shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); +shost_rd_attr(can_queue, "%hd\n"); shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); @@ -200,6 +201,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unique_id, &class_device_attr_host_busy, &class_device_attr_cmd_per_lun, + &class_device_attr_can_queue, &class_device_attr_sg_tablesize, &class_device_attr_unchecked_isa_dma, &class_device_attr_proc_name, diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 7b0019cccce..9b25124a989 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -21,7 +21,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/module.h> -#include <linux/mempool.h> #include <linux/mutex.h> #include <net/tcp.h> #include <scsi/scsi.h> @@ -34,7 +33,7 @@ #define ISCSI_SESSION_ATTRS 11 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 0 -#define ISCSI_TRANSPORT_VERSION "2.0-685" +#define ISCSI_TRANSPORT_VERSION "2.0-724" struct iscsi_internal { int daemon_pid; @@ -149,30 +148,6 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class, static struct sock *nls; static DEFINE_MUTEX(rx_queue_mutex); -struct mempool_zone { - mempool_t *pool; - atomic_t allocated; - int size; - int hiwat; - struct list_head freequeue; - spinlock_t freelock; -}; - -static struct mempool_zone *z_reply; - -/* - * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time - * Z_HIWAT_* - zone's high watermark when if_error bit will be set to -ENOMEM - * so daemon will notice OOM on NETLINK tranposrt level and will - * be able to predict or change operational behavior - */ -#define Z_MAX_REPLY 8 -#define Z_HIWAT_REPLY 6 -#define Z_MAX_PDU 8 -#define Z_HIWAT_PDU 6 -#define Z_MAX_ERROR 16 -#define Z_HIWAT_ERROR 12 - static LIST_HEAD(sesslist); static DEFINE_SPINLOCK(sesslock); static LIST_HEAD(connlist); @@ -414,59 +389,11 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_destroy_session); -static void mempool_zone_destroy(struct mempool_zone *zp) -{ - mempool_destroy(zp->pool); - kfree(zp); -} - -static void* -mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) -{ - struct mempool_zone *zone = pool_data; - - return alloc_skb(zone->size, gfp_mask); -} - -static void -mempool_zone_free_skb(void *element, void *pool_data) -{ - kfree_skb(element); -} - -static struct mempool_zone * -mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) -{ - struct mempool_zone *zp; - - zp = kzalloc(sizeof(*zp), GFP_KERNEL); - if (!zp) - return NULL; - - zp->size = size; - zp->hiwat = hiwat; - INIT_LIST_HEAD(&zp->freequeue); - spin_lock_init(&zp->freelock); - atomic_set(&zp->allocated, 0); - - zp->pool = mempool_create(max, mempool_zone_alloc_skb, - mempool_zone_free_skb, zp); - if (!zp->pool) { - kfree(zp); - return NULL; - } - - return zp; -} - static void iscsi_conn_release(struct device *dev) { struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; - mempool_zone_destroy(conn->z_pdu); - mempool_zone_destroy(conn->z_error); - kfree(conn); put_device(parent); } @@ -476,31 +403,6 @@ static int iscsi_is_conn_dev(const struct device *dev) return dev->release == iscsi_conn_release; } -static int iscsi_create_event_pools(struct iscsi_cls_conn *conn) -{ - conn->z_pdu = mempool_zone_init(Z_MAX_PDU, - NLMSG_SPACE(sizeof(struct iscsi_uevent) + - sizeof(struct iscsi_hdr) + - DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), - Z_HIWAT_PDU); - if (!conn->z_pdu) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "pdu zone for new conn\n"); - return -ENOMEM; - } - - conn->z_error = mempool_zone_init(Z_MAX_ERROR, - NLMSG_SPACE(sizeof(struct iscsi_uevent)), - Z_HIWAT_ERROR); - if (!conn->z_error) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "error zone for new conn\n"); - mempool_zone_destroy(conn->z_pdu); - return -ENOMEM; - } - return 0; -} - /** * iscsi_create_conn - create iscsi class connection * @session: iscsi cls session @@ -533,12 +435,9 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->transport = transport; conn->cid = cid; - if (iscsi_create_event_pools(conn)) - goto free_conn; - /* this is released in the dev's release function */ if (!get_device(&session->dev)) - goto free_conn_pools; + goto free_conn; snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", session->sid, cid); @@ -555,8 +454,6 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) release_parent_ref: put_device(&session->dev); -free_conn_pools: - free_conn: kfree(conn); return NULL; @@ -599,81 +496,31 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt) return NULL; } -static inline struct list_head *skb_to_lh(struct sk_buff *skb) -{ - return (struct list_head *)&skb->cb; -} - -static void -mempool_zone_complete(struct mempool_zone *zone) -{ - unsigned long flags; - struct list_head *lh, *n; - - spin_lock_irqsave(&zone->freelock, flags); - list_for_each_safe(lh, n, &zone->freequeue) { - struct sk_buff *skb = (struct sk_buff *)((char *)lh - - offsetof(struct sk_buff, cb)); - if (!skb_shared(skb)) { - list_del(skb_to_lh(skb)); - mempool_free(skb, zone->pool); - atomic_dec(&zone->allocated); - } - } - spin_unlock_irqrestore(&zone->freelock, flags); -} - -static struct sk_buff* -mempool_zone_get_skb(struct mempool_zone *zone) -{ - struct sk_buff *skb; - - skb = mempool_alloc(zone->pool, GFP_ATOMIC); - if (skb) - atomic_inc(&zone->allocated); - return skb; -} - static int -iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb, gfp_t gfp) +iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp) { - unsigned long flags; int rc; - skb_get(skb); 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); return rc; } - spin_lock_irqsave(&zone->freelock, flags); - INIT_LIST_HEAD(skb_to_lh(skb)); - list_add(skb_to_lh(skb), &zone->freequeue); - spin_unlock_irqrestore(&zone->freelock, flags); return 0; } static int -iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid) +iscsi_unicast_skb(struct sk_buff *skb, int pid) { - unsigned long flags; int rc; - skb_get(skb); rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT); if (rc < 0) { - mempool_free(skb, zone->pool); printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc); return rc; } - spin_lock_irqsave(&zone->freelock, flags); - INIT_LIST_HEAD(skb_to_lh(skb)); - list_add(skb_to_lh(skb), &zone->freequeue); - spin_unlock_irqrestore(&zone->freelock, flags); - return 0; } @@ -692,9 +539,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, if (!priv) return -EINVAL; - mempool_zone_complete(conn->z_pdu); - - skb = mempool_zone_get_skb(conn->z_pdu); + skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " @@ -707,15 +552,13 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, memset(ev, 0, sizeof(*ev)); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_RECV_PDU; - if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) - ev->iferror = -ENOMEM; ev->r.recv_req.cid = conn->cid; ev->r.recv_req.sid = iscsi_conn_get_sid(conn); pdu = (char*)ev + sizeof(*ev); memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); - return iscsi_unicast_skb(conn->z_pdu, skb, priv->daemon_pid); + return iscsi_unicast_skb(skb, priv->daemon_pid); } EXPORT_SYMBOL_GPL(iscsi_recv_pdu); @@ -731,9 +574,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) if (!priv) return; - mempool_zone_complete(conn->z_error); - - skb = mempool_zone_get_skb(conn->z_error); + skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " "conn error (%d)\n", error); @@ -744,13 +585,11 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_CONN_ERROR; - if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat) - ev->iferror = -ENOMEM; ev->r.connerror.error = error; ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC); + iscsi_broadcast_skb(skb, GFP_ATOMIC); dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", error); @@ -767,9 +606,7 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, int flags = multi ? NLM_F_MULTI : 0; int t = done ? NLMSG_DONE : type; - mempool_zone_complete(z_reply); - - skb = mempool_zone_get_skb(z_reply); + skb = alloc_skb(len, GFP_ATOMIC); /* * FIXME: * user is supposed to react on iferror == -ENOMEM; @@ -780,7 +617,7 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); nlh->nlmsg_flags = flags; memcpy(NLMSG_DATA(nlh), payload, size); - return iscsi_unicast_skb(z_reply, skb, pid); + return iscsi_unicast_skb(skb, pid); } static int @@ -810,9 +647,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) do { int actual_size; - mempool_zone_complete(conn->z_pdu); - - skbstat = mempool_zone_get_skb(conn->z_pdu); + skbstat = alloc_skb(len, GFP_ATOMIC); if (!skbstat) { dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " "deliver stats: OOM\n"); @@ -825,8 +660,6 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) memset(evstat, 0, sizeof(*evstat)); evstat->transport_handle = iscsi_handle(conn->transport); evstat->type = nlh->nlmsg_type; - if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) - evstat->iferror = -ENOMEM; evstat->u.get_stats.cid = ev->u.get_stats.cid; evstat->u.get_stats.sid = @@ -845,7 +678,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) skb_trim(skbstat, NLMSG_ALIGN(actual_size)); nlhstat->nlmsg_len = actual_size; - err = iscsi_unicast_skb(conn->z_pdu, skbstat, priv->daemon_pid); + err = iscsi_unicast_skb(skbstat, priv->daemon_pid); } while (err < 0 && err != -ECONNREFUSED); return err; @@ -876,9 +709,7 @@ int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) session = iscsi_dev_to_session(conn->dev.parent); shost = iscsi_session_to_shost(session); - mempool_zone_complete(conn->z_pdu); - - skb = mempool_zone_get_skb(conn->z_pdu); + skb = alloc_skb(len, GFP_KERNEL); if (!skb) { dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event\n"); @@ -896,7 +727,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, GFP_KERNEL); + rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session destruction event. Check iscsi daemon\n"); @@ -939,9 +770,7 @@ int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) session = iscsi_dev_to_session(conn->dev.parent); shost = iscsi_session_to_shost(session); - mempool_zone_complete(conn->z_pdu); - - skb = mempool_zone_get_skb(conn->z_pdu); + skb = alloc_skb(len, GFP_KERNEL); if (!skb) { dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event\n"); @@ -959,7 +788,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, GFP_KERNEL); + rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event. Check iscsi daemon\n"); @@ -1278,9 +1107,6 @@ iscsi_if_rx(struct sock *sk, int len) err = iscsi_if_send_reply( NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); - if (atomic_read(&z_reply->allocated) >= - z_reply->hiwat) - ev->iferror = -ENOMEM; } while (err < 0 && err != -ECONNREFUSED); skb_pull(skb, rlen); } @@ -1584,32 +1410,6 @@ int iscsi_unregister_transport(struct iscsi_transport *tt) } EXPORT_SYMBOL_GPL(iscsi_unregister_transport); -static int -iscsi_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct netlink_notify *n = ptr; - - if (event == NETLINK_URELEASE && - n->protocol == NETLINK_ISCSI && n->pid) { - struct iscsi_cls_conn *conn; - unsigned long flags; - - mempool_zone_complete(z_reply); - spin_lock_irqsave(&connlock, flags); - list_for_each_entry(conn, &connlist, conn_list) { - mempool_zone_complete(conn->z_error); - mempool_zone_complete(conn->z_pdu); - } - spin_unlock_irqrestore(&connlock, flags); - } - - return NOTIFY_DONE; -} - -static struct notifier_block iscsi_nl_notifier = { - .notifier_call = iscsi_rcv_nl_event, -}; - static __init int iscsi_transport_init(void) { int err; @@ -1633,25 +1433,15 @@ static __init int iscsi_transport_init(void) if (err) goto unregister_conn_class; - err = netlink_register_notifier(&iscsi_nl_notifier); - if (err) - goto unregister_session_class; - nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, THIS_MODULE); if (!nls) { err = -ENOBUFS; - goto unregister_notifier; + goto unregister_session_class; } - z_reply = mempool_zone_init(Z_MAX_REPLY, - NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY); - if (z_reply) - return 0; + return 0; - sock_release(nls->sk_socket); -unregister_notifier: - netlink_unregister_notifier(&iscsi_nl_notifier); unregister_session_class: transport_class_unregister(&iscsi_session_class); unregister_conn_class: @@ -1665,9 +1455,7 @@ unregister_transport_class: static void __exit iscsi_transport_exit(void) { - mempool_zone_destroy(z_reply); sock_release(nls->sk_socket); - netlink_unregister_notifier(&iscsi_nl_notifier); transport_class_unregister(&iscsi_connection_class); transport_class_unregister(&iscsi_session_class); transport_class_unregister(&iscsi_host_class); diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 8ff1f2866f7..5ffec2721b2 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -97,8 +97,8 @@ #include <linux/blkdev.h> #include <linux/stat.h> #include <linux/delay.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 3f8b9318856..81e3bc7b02a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include <linux/proc_fs.h> -static char *sg_version_date = "20060920"; +static char *sg_version_date = "20061027"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -710,12 +710,12 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, (int) cmnd[0], (int) hp->cmd_len)); if ((k = sg_start_req(srp))) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k)); + SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k)); sg_finish_rem_req(srp); return k; /* probably out of space --> ENOMEM */ } if ((k = sg_write_xfer(srp))) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_common_write: write_xfer, bad address\n")); sg_finish_rem_req(srp); return k; } @@ -746,7 +746,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, hp->dxfer_len, srp->data.k_use_sg, timeout, SG_DEFAULT_RETRIES, srp, sg_cmd_done, GFP_ATOMIC)) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: scsi_execute_async failed\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_common_write: scsi_execute_async failed\n")); /* * most likely out of mem, but could also be a bad map */ @@ -1283,7 +1283,7 @@ sg_cmd_done(void *data, char *sense, int result, int resid) sg_finish_rem_req(srp); srp = NULL; if (NULL == sfp->headrp) { - SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, final cleanup\n")); if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ scsi_device_put(sdp->device); } @@ -1512,12 +1512,12 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) POLL_HUP); } } - SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k)); + SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k)); if (NULL == sdp->headfp) { sg_dev_arr[k] = NULL; } } else { /* nothing active, simple case */ - SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); + SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k)); sg_dev_arr[k] = NULL; } sg_nr_dev--; @@ -1876,14 +1876,15 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) } } sg->page = p; - sg->length = ret_sz; + sg->length = (ret_sz > num) ? num : ret_sz; - SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d\n", - k, p, ret_sz)); + SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, " + "ret_sz=%d\n", k, num, ret_sz)); } /* end of for loop */ schp->k_use_sg = k; - SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, rem_sz=%d\n", k, rem_sz)); + SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, " + "rem_sz=%d\n", k, rem_sz)); schp->bufflen = blk_size; if (rem_sz > 0) /* must have failed */ @@ -2014,7 +2015,7 @@ sg_remove_scat(Sg_scatter_hold * schp) for (k = 0; (k < schp->k_use_sg) && sg->page; ++k, ++sg) { SCSI_LOG_TIMEOUT(5, printk( - "sg_remove_scat: k=%d, a=0x%p, len=%d\n", + "sg_remove_scat: k=%d, pg=0x%p, len=%d\n", k, sg->page, sg->length)); sg_page_free(sg->page, sg->length); } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index febfac97ad3..587274dd705 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -1177,7 +1177,10 @@ static int st_open(struct inode *inode, struct file *filp) goto err_out; if ((filp->f_flags & O_NONBLOCK) == 0 && retval != CHKRES_READY) { - retval = (-EIO); + if (STp->ready == NO_TAPE) + retval = (-ENOMEDIUM); + else + retval = (-EIO); goto err_out; } return 0; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 5ec5af8e337..3b3f3050a87 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -266,8 +266,8 @@ static struct scsi_host_template *the_template = NULL; (struct NCR5380_hostdata *)(in)->hostdata #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) -#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble)) -#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) +#define NEXT(cmd) ((struct scsi_cmnd *)((cmd)->host_scribble)) +#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble)) #define HOSTNO instance->host_no #define H_NO(cmd) (cmd)->device->host->host_no @@ -360,7 +360,7 @@ static void __init init_tags( void ) * conditions. */ -static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) +static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged) { SETUP_HOSTDATA(cmd->device->host); @@ -384,7 +384,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) * untagged. */ -static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) +static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged) { SETUP_HOSTDATA(cmd->device->host); @@ -416,7 +416,7 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) * unlock the LUN. */ -static void cmd_free_tag( Scsi_Cmnd *cmd ) +static void cmd_free_tag(struct scsi_cmnd *cmd) { SETUP_HOSTDATA(cmd->device->host); @@ -460,18 +460,18 @@ static void free_all_tags( void ) /* - * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd ) + * Function: void merge_contiguous_buffers(struct scsi_cmnd *cmd) * * Purpose: Try to merge several scatter-gather requests into one DMA * transfer. This is possible if the scatter buffers lie on * physical contiguous addresses. * - * Parameters: Scsi_Cmnd *cmd + * Parameters: struct scsi_cmnd *cmd * The command to work on. The first scatter buffer's data are * assumed to be already transfered into ptr/this_residual. */ -static void merge_contiguous_buffers( Scsi_Cmnd *cmd ) +static void merge_contiguous_buffers(struct scsi_cmnd *cmd) { unsigned long endaddr; #if (NDEBUG & NDEBUG_MERGING) @@ -501,15 +501,15 @@ static void merge_contiguous_buffers( Scsi_Cmnd *cmd ) } /* - * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * Function : void initialize_SCp(struct scsi_cmnd *cmd) * * Purpose : initialize the saved data pointers for cmd to point to the * start of the buffer. * - * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + * Inputs : cmd - struct scsi_cmnd structure to have pointers reset. */ -static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) +static __inline__ void initialize_SCp(struct scsi_cmnd *cmd) { /* * Initialize the Scsi Pointer field so that all of the commands in the @@ -753,14 +753,15 @@ static void NCR5380_print_status (struct Scsi_Host *instance) do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ pos += sprintf(pos, fmt , ## args); } while(0) static -char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); +char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer, + int length); -static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, - off_t offset, int length, int inout) +static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, + char **start, off_t offset, int length, int inout) { char *pos = buffer; struct NCR5380_hostdata *hostdata; - Scsi_Cmnd *ptr; + struct scsi_cmnd *ptr; unsigned long flags; off_t begin = 0; #define check_offset() \ @@ -784,18 +785,19 @@ static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **s if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", HOSTNO); else - pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, + pos = lprint_Scsi_Cmnd ((struct scsi_cmnd *) hostdata->connected, pos, buffer, length); SPRINTF("scsi%d: issue_queue\n", HOSTNO); check_offset(); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { + for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) + { pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); check_offset(); } SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); check_offset(); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; + for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = NEXT(ptr)) { pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); check_offset(); @@ -810,8 +812,8 @@ static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **s return length; } -static char * -lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) +static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer, + int length) { int i, s; unsigned char *command; @@ -888,8 +890,8 @@ static int NCR5380_init (struct Scsi_Host *instance, int flags) } /* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) + * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd, + * void (*done)(struct scsi_cmnd *)) * * Purpose : enqueues a SCSI command * @@ -906,10 +908,11 @@ static int NCR5380_init (struct Scsi_Host *instance, int flags) */ /* Only make static if a wrapper function is used */ -static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int NCR5380_queue_command(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) { SETUP_HOSTDATA(cmd->device->host); - Scsi_Cmnd *tmp; + struct scsi_cmnd *tmp; unsigned long flags; #if (NDEBUG & NDEBUG_NO_WRITE) @@ -990,7 +993,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = cmd; } else { - for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; + for (tmp = (struct scsi_cmnd *)hostdata->issue_queue; NEXT(tmp); tmp = NEXT(tmp)) ; LIST(cmd, tmp); @@ -1030,7 +1033,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) static void NCR5380_main (void *bl) { - Scsi_Cmnd *tmp, *prev; + struct scsi_cmnd *tmp, *prev; struct Scsi_Host *instance = first_instance; struct NCR5380_hostdata *hostdata = HOSTDATA(instance); int done; @@ -1073,12 +1076,12 @@ static void NCR5380_main (void *bl) * for a target that's not busy. */ #if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; + for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) ; if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ #endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, + for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { #if (NDEBUG & NDEBUG_LISTS) @@ -1339,7 +1342,8 @@ static irqreturn_t NCR5380_intr (int irq, void *dev_id) } #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) +static void collect_stats(struct NCR5380_hostdata *hostdata, + struct scsi_cmnd *cmd) { # ifdef NCR5380_STAT_LIMIT if (cmd->request_bufflen > NCR5380_STAT_LIMIT) @@ -1365,8 +1369,8 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) #endif /* - * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, - * int tag); + * Function : int NCR5380_select(struct Scsi_Host *instance, + * struct scsi_cmnd *cmd, int tag); * * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, * including ARBITRATION, SELECTION, and initial message out for @@ -1395,7 +1399,8 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) * cmd->result host byte set to DID_BAD_TARGET. */ -static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) +static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd, + int tag) { SETUP_HOSTDATA(instance); unsigned char tmp[3], phase; @@ -1985,7 +1990,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) #endif unsigned char *data; unsigned char phase, tmp, extended_msg[10], old_phase=0xff; - Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected; #ifdef SUN3_SCSI_VME dregs->csr |= CSR_INTR; @@ -2272,7 +2277,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) local_irq_save(flags); LIST(cmd,hostdata->issue_queue); NEXT(cmd) = hostdata->issue_queue; - hostdata->issue_queue = (Scsi_Cmnd *) cmd; + hostdata->issue_queue = (struct scsi_cmnd *) cmd; local_irq_restore(flags); QU_PRINTK("scsi%d: REQUEST SENSE added to head of " "issue queue\n", H_NO(cmd)); @@ -2502,7 +2507,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) * Function : void NCR5380_reselect (struct Scsi_Host *instance) * * Purpose : does reselection, initializing the instance->connected - * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * field to point to the struct scsi_cmnd for which the I_T_L or I_T_L_Q * nexus has been reestablished, * * Inputs : instance - this instance of the NCR5380. @@ -2521,7 +2526,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) unsigned char tag; #endif unsigned char msg[3]; - Scsi_Cmnd *tmp = NULL, *prev; + struct scsi_cmnd *tmp = NULL, *prev; /* unsigned long flags; */ /* @@ -2577,7 +2582,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) * just reestablished, and remove it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) #ifdef SUPPORT_TAGS @@ -2668,11 +2673,11 @@ static void NCR5380_reselect (struct Scsi_Host *instance) /* - * Function : int NCR5380_abort (Scsi_Cmnd *cmd) + * Function : int NCR5380_abort(struct scsi_cmnd *cmd) * * Purpose : abort a command * - * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the + * Inputs : cmd - the struct scsi_cmnd to abort, code - code to set the * host byte of the result field to, if zero DID_ABORTED is * used. * @@ -2684,11 +2689,11 @@ static void NCR5380_reselect (struct Scsi_Host *instance) * called where the loop started in NCR5380_main(). */ -static int NCR5380_abort (Scsi_Cmnd *cmd) +static int NCR5380_abort(struct scsi_cmnd *cmd) { struct Scsi_Host *instance = cmd->device->host; SETUP_HOSTDATA(instance); - Scsi_Cmnd *tmp, **prev; + struct scsi_cmnd *tmp, **prev; unsigned long flags; printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); @@ -2753,9 +2758,9 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) * Case 2 : If the command hasn't been issued yet, we simply remove it * from the issue queue. */ - for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), - tmp = (Scsi_Cmnd *) hostdata->issue_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), + tmp = (struct scsi_cmnd *) hostdata->issue_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) if (cmd == tmp) { REMOVE(5, *prev, tmp, NEXT(tmp)); (*prev) = NEXT(tmp); @@ -2812,7 +2817,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) * it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; tmp = NEXT(tmp)) if (cmd == tmp) { local_irq_restore(flags); @@ -2826,8 +2831,8 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) do_abort (instance); local_irq_save(flags); - for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; + for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), + tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) if (cmd == tmp) { REMOVE(5, *prev, tmp, NEXT(tmp)); @@ -2868,7 +2873,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) /* - * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd) + * Function : int NCR5380_bus_reset(struct scsi_cmnd *cmd) * * Purpose : reset the SCSI bus. * @@ -2876,13 +2881,13 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) * */ -static int NCR5380_bus_reset( Scsi_Cmnd *cmd) +static int NCR5380_bus_reset(struct scsi_cmnd *cmd) { SETUP_HOSTDATA(cmd->device->host); int i; unsigned long flags; #if 1 - Scsi_Cmnd *connected, *disconnected_queue; + struct scsi_cmnd *connected, *disconnected_queue; #endif @@ -2914,9 +2919,9 @@ static int NCR5380_bus_reset( Scsi_Cmnd *cmd) * remembered in local variables first. */ local_irq_save(flags); - connected = (Scsi_Cmnd *)hostdata->connected; + connected = (struct scsi_cmnd *)hostdata->connected; hostdata->connected = NULL; - disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; + disconnected_queue = (struct scsi_cmnd *)hostdata->disconnected_queue; hostdata->disconnected_queue = NULL; #ifdef SUPPORT_TAGS free_all_tags(); diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index e625b4c5833..d56d85dd9ba 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -119,7 +119,7 @@ module_param(setup_use_tagged_queuing, int, 0); static int setup_hostid = -1; module_param(setup_hostid, int, 0); -static Scsi_Cmnd *sun3_dma_setup_done = NULL; +static struct scsi_cmnd *sun3_dma_setup_done = NULL; #define AFTER_RESET_DELAY (HZ/2) @@ -521,8 +521,9 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) return last_residual; } -static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, - int write_flag) +static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, + struct scsi_cmnd *cmd, + int write_flag) { if(blk_fs_request(cmd->request)) return wanted; diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h index 834dab42801..a1103b3e203 100644 --- a/drivers/scsi/sun3_scsi.h +++ b/drivers/scsi/sun3_scsi.h @@ -47,11 +47,12 @@ #define IOBASE_SUN3_VMESCSI 0xff200000 -static int sun3scsi_abort (Scsi_Cmnd *); +static int sun3scsi_abort(struct scsi_cmnd *); static int sun3scsi_detect (struct scsi_host_template *); static const char *sun3scsi_info (struct Scsi_Host *); -static int sun3scsi_bus_reset(Scsi_Cmnd *); -static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int sun3scsi_bus_reset(struct scsi_cmnd *); +static int sun3scsi_queue_command(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); static int sun3scsi_release (struct Scsi_Host *); #ifndef CMD_PER_LUN diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index e8faab16567..92def310a84 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -84,7 +84,7 @@ module_param(setup_use_tagged_queuing, int, 0); static int setup_hostid = -1; module_param(setup_hostid, int, 0); -static Scsi_Cmnd *sun3_dma_setup_done = NULL; +static struct scsi_cmnd *sun3_dma_setup_done = NULL; #define AFTER_RESET_DELAY (HZ/2) @@ -455,8 +455,9 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) return last_residual; } -static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, - int write_flag) +static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, + struct scsi_cmnd *cmd, + int write_flag) { if(blk_fs_request(cmd->request)) return wanted; diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index 2df6747cb76..0b7a70f61e0 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -109,7 +109,7 @@ #include <asm/system.h> #include <linux/signal.h> #include <linux/sched.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/blkdev.h> #include <linux/interrupt.h> #include <linux/stat.h> diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index d03aa6ce8fe..fa5382e354b 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -2304,6 +2304,7 @@ static struct scsi_host_template driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .max_sectors = 0x4000, /* 8MiB = 16 * 1024 * 512 */ }; /*********************************************************************** diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 331e1cf159b..30be76514c4 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -178,10 +178,10 @@ #include <linux/blkdev.h> #include <linux/init.h> #include <linux/stat.h> +#include <linux/io.h> #include <asm/system.h> #include <asm/dma.h> -#include <asm/io.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b0d502622d9..0b71e7d1890 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -767,37 +767,37 @@ config SERIAL_CPM_SCC1 bool "Support for SCC1 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC1 as a serial port + Select this option to use SCC1 as a serial port config SERIAL_CPM_SCC2 bool "Support for SCC2 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC2 as a serial port + Select this option to use SCC2 as a serial port config SERIAL_CPM_SCC3 bool "Support for SCC3 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC3 as a serial port + Select this option to use SCC3 as a serial port config SERIAL_CPM_SCC4 bool "Support for SCC4 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC4 as a serial port + Select this option to use SCC4 as a serial port config SERIAL_CPM_SMC1 bool "Support for SMC1 serial port" depends on SERIAL_CPM=y help - Select the is option to use SMC1 as a serial port + Select this option to use SMC1 as a serial port config SERIAL_CPM_SMC2 bool "Support for SMC2 serial port" depends on SERIAL_CPM=y help - Select the is option to use SMC2 as a serial port + Select this option to use SMC2 as a serial port config SERIAL_SGI_L1_CONSOLE bool "SGI Altix L1 serial console support" diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index a8f894c7819..69715e55650 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -88,7 +88,7 @@ extern struct uart_cpm_port cpm_uart_ports[UART_NR]; /* these are located in their respective files */ void cpm_line_cr_cmd(int line, int cmd); -int cpm_uart_init_portdesc(void); +int __init cpm_uart_init_portdesc(void); int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); void cpm_uart_freebuf(struct uart_cpm_port *pinfo); diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 0abb544ae63..7a3b97fdf8d 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -195,10 +195,8 @@ static void cpm_uart_start_tx(struct uart_port *port) if (cpm_uart_tx_pump(port) != 0) { if (IS_SMC(pinfo)) { smcp->smc_smcm |= SMCM_TX; - smcp->smc_smcmr |= SMCMR_TEN; } else { sccp->scc_sccm |= UART_SCCM_TX; - pinfo->sccp->scc_gsmrl |= SCC_GSMRL_ENT; } } } @@ -421,9 +419,10 @@ static int cpm_uart_startup(struct uart_port *port) /* Startup rx-int */ if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm |= SMCM_RX; - pinfo->smcp->smc_smcmr |= SMCMR_REN; + pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); } else { pinfo->sccp->scc_sccm |= UART_SCCM_RX; + pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); } if (!(pinfo->flags & FLAG_CONSOLE)) @@ -1350,11 +1349,10 @@ static int cpm_uart_init(void) { pr_info("cpm_uart: WARNING: no UART devices found on platform bus!\n"); pr_info( "cpm_uart: the driver will guess configuration, but this mode is no longer supported.\n"); -#ifndef CONFIG_SERIAL_CPM_CONSOLE - ret = cpm_uart_init_portdesc(); - if (ret) - return ret; -#endif + + /* Don't run this again, if the console driver did it already */ + if (cpm_uart_nr == 0) + cpm_uart_init_portdesc(); cpm_reg.nr = cpm_uart_nr; ret = uart_register_driver(&cpm_reg); @@ -1366,6 +1364,8 @@ static int cpm_uart_init(void) { int con = cpm_uart_port_map[i]; cpm_uart_ports[con].port.line = i; cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; + if (cpm_uart_ports[con].set_lineif) + cpm_uart_ports[con].set_lineif(&cpm_uart_ports[con]); uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); } diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 95afc37297a..08e55fdc882 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -184,7 +184,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) } /* Setup any dynamic params in the uart desc */ -int cpm_uart_init_portdesc(void) +int __init cpm_uart_init_portdesc(void) { pr_debug("CPM uart[-]:init portdesc\n"); diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 98ce88d8020..711bd151143 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -921,7 +921,7 @@ static void handle_dma_error_intr(void *arg, uint32_t other_ir) { struct ioc4_port *port = (struct ioc4_port *)arg; struct hooks *hooks = port->ip_hooks; - unsigned int flags; + unsigned long flags; spin_lock_irqsave(&port->ip_lock, flags); @@ -1834,7 +1834,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) struct ioc4_port *port = (struct ioc4_port *)arg; struct hooks *hooks = port->ip_hooks; unsigned int rx_high_rd_aborted = 0; - unsigned int flags; + unsigned long flags; struct uart_port *the_port; int loop_counter; @@ -2935,7 +2935,7 @@ static void __devexit ioc4_serial_exit(void) uart_unregister_driver(&ioc4_uart_rs422); } -module_init(ioc4_serial_init); +late_initcall(ioc4_serial_init); /* Call only after tty init is done */ module_exit(ioc4_serial_exit); MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>"); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 266aa325569..cfcc3caf49d 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -808,7 +808,7 @@ static int sci_request_irq(struct sci_port *port) } if (request_irq(port->irqs[0], sci_mpxed_interrupt, - SA_INTERRUPT, "sci", port)) { + IRQF_DISABLED, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } @@ -817,7 +817,7 @@ static int sci_request_irq(struct sci_port *port) if (!port->irqs[i]) continue; if (request_irq(port->irqs[i], handlers[i], - SA_INTERRUPT, desc[i], port)) { + IRQF_DISABLED, desc[i], port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 73dd2eedaaa..b2cc703b2b9 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1182,7 +1182,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) return 0; } -static struct console sunzilog_console = { +static struct console sunzilog_console_ops = { .name = "ttyS", .write = sunzilog_console_write, .device = uart_console_device, @@ -1208,10 +1208,10 @@ static inline struct console *SUNZILOG_CONSOLE(void) if (i == NUM_CHANNELS) return NULL; - sunzilog_console.index = i; + sunzilog_console_ops.index = i; sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; - return &sunzilog_console; + return &sunzilog_console_ops; } #else diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig index a3473162587..c66ba9ad833 100644 --- a/drivers/sn/Kconfig +++ b/drivers/sn/Kconfig @@ -5,19 +5,6 @@ menu "SN Devices" depends on SGI_SN -config SGI_IOC4 - tristate "SGI IOC4 Base IO support" - depends on MMTIMER - default m - ---help--- - This option enables basic support for the SGI IOC4-based Base IO - controller card. This option does not enable any specific - functions on such a card, but provides necessary infrastructure - for other drivers to utilize. - - If you have an SGI Altix with an IOC4-based - I/O controller say Y. Otherwise say N. - config SGI_IOC3 tristate "SGI IOC3 Base IO support" default m diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile index 2cda011597c..693db8bb8d9 100644 --- a/drivers/sn/Makefile +++ b/drivers/sn/Makefile @@ -3,5 +3,4 @@ # # -obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SGI_IOC3) += ioc3.o diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 146298ad737..c3c0626f550 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -281,7 +281,6 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) up(&board_lock); return 0; } -EXPORT_SYMBOL_GPL(spi_register_board_info); /* FIXME someone should add support for a __setup("spi", ...) that * creates board info from kernel command lines diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index f6b2948ab28..1b601b6cf2a 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -284,6 +284,14 @@ static int samplerate = 100; module_param(ixjdebug, int, 0); +static struct pci_device_id ixj_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, ixj_pci_tbl); + /************************************************************************ * * ixjdebug meanings are now bit mapped instead of level based @@ -7683,7 +7691,8 @@ static int __init ixj_probe_pci(int *cnt) IXJ *j = NULL; for (i = 0; i < IXJMAX - *cnt; i++) { - pci = pci_find_device(0x15E2, 0x0500, pci); + pci = pci_find_device(PCI_VENDOR_ID_QUICKNET, + PCI_DEVICE_ID_QUICKNET_XJ, pci); if (!pci) break; diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h index fbea4541c23..8d69bcdc29c 100644 --- a/drivers/telephony/ixj.h +++ b/drivers/telephony/ixj.h @@ -1295,7 +1295,7 @@ typedef struct { Proc_Info_Type Info_write; unsigned short frame_count; unsigned int filter_hist[4]; - unsigned char filter_en[4]; + unsigned char filter_en[6]; unsigned short proc_load; unsigned long framesread; unsigned long frameswritten; diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 97d57cfc343..825bf884537 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_USB_KBTAB) += input/ obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_POWERMATE) += input/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/ obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_XPAD) += input/ @@ -66,6 +65,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_SISUSBVGA) += misc/ obj-$(CONFIG_USB_TEST) += misc/ +obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_ATM) += atm/ diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 3892a9e9aee..e6565633ba0 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -793,6 +793,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { { /* V = Conexant P = ADSL modem */ USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 }, + { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */ + USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00 + }, { /* V = Olitec P = ADSL modem version 2 */ USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe }, diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 7c7b507af29..c870c804470 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch"; #define OFFSET_d 9 /* size 4 */ #define OFFSET_e 13 /* size 1 */ #define OFFSET_f 14 /* size 1 */ -#define TOTAL 15 #define SIZE_7 1 #define SIZE_b 8 @@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST; static int enable_isoc = DEFAULT_ENABLE_ISOC; static int sw_buffering = DEFAULT_SW_BUFFERING; +#define DEFAULT_B_MAX_DSL 8128 +#define DEFAULT_MODEM_MODE 11 +#define MODEM_OPTION_LENGTH 16 +static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { + 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; +static unsigned char ModemMode = DEFAULT_MODEM_MODE; +static unsigned char ModemOption[MODEM_OPTION_LENGTH]; +static int num_ModemOption; + module_param(altsetting, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(altsetting, "Alternative setting for data interface (bulk_default: " @@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering, "Enable software buffering (default: " __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); +module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(BMaxDSL, + "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL)); + +module_param(ModemMode, byte, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ModemMode, + "default: " __MODULE_STRING(DEFAULT_MODEM_MODE)); + +module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO); +MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20"); + #define INTERFACE_DATA 1 #define ENDPOINT_INT 0x81 #define ENDPOINT_BULK_DATA 0x07 @@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering, #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) +struct speedtch_params { + unsigned int altsetting; + unsigned int BMaxDSL; + unsigned char ModemMode; + unsigned char ModemOption[MODEM_OPTION_LENGTH]; +}; + struct speedtch_instance_data { struct usbatm_data *usbatm; - unsigned int altsetting; + struct speedtch_params params; /* set in probe, constant afterwards */ struct work_struct status_checker; @@ -123,7 +152,7 @@ struct speedtch_instance_data { struct urb *int_urb; unsigned char int_data[16]; - unsigned char scratch_buffer[TOTAL]; + unsigned char scratch_buffer[16]; }; /*************** @@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance) 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); if (ret < 0) usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); + + /* Extra initialisation in recent drivers - gives higher speeds */ + + /* URBext1 */ + buf[0] = instance->params.ModemMode; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret); + + /* URBext2 */ + /* This seems to be the one which actually triggers the higher sync + rate -- it does require the new firmware too, although it works OK + with older firmware */ + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x14, 0x00, + instance->params.ModemOption, + MODEM_OPTION_LENGTH, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret); + + /* URBext3 */ + buf[0] = instance->params.BMaxDSL & 0xff; + buf[1] = instance->params.BMaxDSL >> 8; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret); } static int speedtch_upload_firmware(struct speedtch_instance_data *instance, @@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, because we're in our own kernel thread anyway. */ msleep_interruptible(1000); - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret); + if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { + usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret); goto out_free; } @@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance) unsigned char *buf = instance->scratch_buffer; int ret; - memset(buf, 0, TOTAL); + memset(buf, 0, 16); ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, @@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance->usbatm = usbatm; - /* altsetting and enable_isoc may change at any moment, so take a snapshot */ - instance->altsetting = altsetting; + /* module parameters may change at any moment, so take a snapshot */ + instance->params.altsetting = altsetting; + instance->params.BMaxDSL = BMaxDSL; + instance->params.ModemMode = ModemMode; + memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH); + memcpy(instance->params.ModemOption, ModemOption, num_ModemOption); use_isoc = enable_isoc; - if (instance->altsetting) - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret); - instance->altsetting = 0; /* fall back to default */ + if (instance->params.altsetting) + if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { + usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret); + instance->params.altsetting = 0; /* fall back to default */ } - if (!instance->altsetting && use_isoc) + if (!instance->params.altsetting && use_isoc) if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); use_isoc = 0; /* fall back to bulk */ @@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_data *usbatm, usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); } - if (!use_isoc && !instance->altsetting) + if (!use_isoc && !instance->params.altsetting) if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); goto fail_free; } - if (!instance->altsetting) - instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; + if (!instance->params.altsetting) + instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f5434b1cbb1..f6b9f7e1f71 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -68,7 +68,7 @@ #include "usbatm.h" -#define EAGLEUSBVERSION "ueagle 1.3" +#define EAGLEUSBVERSION "ueagle 1.4" /* @@ -80,14 +80,14 @@ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm dbg] %s: " format, \ __FUNCTION__, ##args); \ - } while (0) + } while (0) #define uea_vdbg(usb_dev, format, args...) \ do { \ if (debug >= 2) \ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm vdbg] " format, ##args); \ - } while (0) + } while (0) #define uea_enters(usb_dev) \ uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__) @@ -218,8 +218,8 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(sc) \ - (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(usb_dev) \ + (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) #define INS_TO_USBDEV(ins) ins->usb_dev @@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc) char *dsp_name; if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc)) + if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc)) + if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_timeout(sc->cmv_ack_wait, + int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, sc->cmv_ack, ACK_TIMEOUT); sc->cmv_ack = 0; @@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc) break; case 3: /* fail ... */ - uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n"); + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc) release_firmware(sc->dsp_firm); sc->dsp_firm = NULL; } - - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); } /* always update it as atm layer could not be init when we switch to @@ -1033,9 +1028,9 @@ static int request_cmvs(struct uea_softc *sc, if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin"; + file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; else - file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin"; + file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; } else file = cmv_file[sc->modem_index]; @@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_softc *sc) if (ret < 0) return ret; + /* Dump firmware version */ + ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + /* get options */ ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); if (ret < 0) @@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_softc *sc) /* Enter in R-ACT-REQ */ ret = uea_write_cmv(sc, SA_CNTL, 0, 2); uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "Modem started, " + "waiting synchronization\n"); out: release_firmware(cmvs_fw); sc->reset = 0; @@ -1172,7 +1176,10 @@ static int uea_kthread(void *data) if (!ret) ret = uea_stat(sc); if (ret != -EAGAIN) - msleep(1000); + msleep_interruptible(1000); + if (try_to_freeze()) + uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " + "please unplug/replug your modem\n"); } uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0); UEA_ATTR(dscorr, 0); UEA_ATTR(usunc, 0); UEA_ATTR(dsunc, 0); +UEA_ATTR(firmid, 0); /* Retrieve the device End System Identifier (MAC) */ @@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf) { struct uea_softc *sc = usbatm->driver_data; - wait_event(sc->sync_q, IS_OPERATIONAL(sc)); + wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc)); return 0; @@ -1639,16 +1647,13 @@ static struct attribute *attrs[] = { &dev_attr_stat_dscorr.attr, &dev_attr_stat_usunc.attr, &dev_attr_stat_dsunc.attr, + &dev_attr_stat_firmid.attr, + NULL, }; static struct attribute_group attr_grp = { .attrs = attrs, }; -static int create_fs_entries(struct usb_interface *intf) -{ - return sysfs_create_group(&intf->dev.kobj, &attr_grp); -} - static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id) { @@ -1708,31 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, } } + ret = sysfs_create_group(&intf->dev.kobj, &attr_grp); + if (ret < 0) + goto error; + ret = uea_boot(sc); - if (ret < 0) { - kfree(sc); - return ret; - } + if (ret < 0) + goto error; - ret = create_fs_entries(intf); - if (ret) { - uea_stop(sc); - kfree(sc); - return ret; - } return 0; -} - -static void destroy_fs_entries(struct usb_interface *intf) -{ - sysfs_remove_group(&intf->dev.kobj, &attr_grp); +error: + kfree(sc); + return ret; } static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) { struct uea_softc *sc = usbatm->driver_data; - destroy_fs_entries(intf); + sysfs_remove_group(&intf->dev.kobj, &attr_grp); uea_stop(sc); kfree(sc); } @@ -1753,10 +1752,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n", + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", le16_to_cpu(usb->descriptor.idVendor), le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)]); + chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); usb_reset_device(usb); diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 309073f6433..ec63b0ee074 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg) daemonize(instance->driver->driver_name); allow_signal(SIGTERM); + instance->thread_pid = current->pid; complete(&instance->thread_started); @@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance) return ret; } - mutex_lock(&instance->serialize); - instance->thread_pid = ret; - mutex_unlock(&instance->serialize); - wait_for_completion(&instance->thread_started); return 0; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ec4d1d75672..9a9012fd284 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm) struct acm_rb *buf; struct tty_struct *tty = acm->tty; struct acm_ru *rcv; - //unsigned long flags; + unsigned long flags; int i = 0; dbg("Entering acm_rx_tasklet"); @@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm) return; next_buffer: - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->filled_read_bufs)) { - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); goto urbs; } buf = list_entry(acm->filled_read_bufs.next, struct acm_rb, list); list_del(&buf->list); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); @@ -356,29 +356,29 @@ next_buffer: memmove(buf->base, buf->base + i, buf->size - i); buf->size -= i; spin_unlock(&acm->throttle_lock); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->filled_read_bufs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } spin_unlock(&acm->throttle_lock); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->spare_read_bufs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); goto next_buffer; urbs: while (!list_empty(&acm->spare_read_bufs)) { - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->spare_read_urbs)) { - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } rcv = list_entry(acm->spare_read_urbs.next, struct acm_ru, list); list_del(&rcv->list); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); buf = list_entry(acm->spare_read_bufs.next, struct acm_rb, list); @@ -400,9 +400,9 @@ urbs: free-urbs-pool and resubmited ASAP */ if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { list_add(&buf->list, &acm->spare_read_bufs); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&rcv->list, &acm->spare_read_urbs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } } @@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ .driver_info = SINGLE_RX_URB, /* firmware bug */ }, diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index a161d70e1e4..6303970e93c 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -154,6 +154,7 @@ struct usblp { unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ + unsigned char sleeping; /* interface is suspended */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) { dbg("quirks=%d", usblp->quirks); dbg("used=%d", usblp->used); dbg("bidir=%d", usblp->bidir); + dbg("sleeping=%d", usblp->sleeping); dbg("device_id_string=\"%s\"", usblp->device_id_string ? usblp->device_id_string + 2 : @@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err) return newerr; } +static int handle_bidir (struct usblp *usblp) +{ + if (usblp->bidir && usblp->used && !usblp->sleeping) { + usblp->readcount = 0; + usblp->readurb->dev = usblp->dev; + if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { + usblp->used = 0; + return -EIO; + } + } + + return 0; +} + /* * File op functions. */ @@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->writeurb->status = 0; usblp->readurb->status = 0; - if (usblp->bidir) { - usblp->readcount = 0; - usblp->readurb->dev = usblp->dev; - if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { - retval = -EIO; - usblp->used = 0; - file->private_data = NULL; - } + if (handle_bidir(usblp) < 0) { + file->private_data = NULL; + retval = -EIO; } out: mutex_unlock (&usblp_mutex); @@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } + if (usblp->sleeping) { + retval = -ENODEV; + goto done; + } + dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); @@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t return -ENODEV; } + if (usblp->sleeping) { + up (&usblp->sem); + return writecount ? writecount : -ENODEV; + } + if (usblp->writeurb->status != 0) { if (usblp->quirks & USBLP_QUIRK_BIDIR) { if (!usblp->wcomplete) @@ -701,6 +722,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usblp->wcomplete = 0; err = usb_submit_urb(usblp->writeurb, GFP_KERNEL); if (err) { + usblp->wcomplete = 1; if (err != -ENOMEM) count = -EIO; else @@ -749,6 +771,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, goto done; } + if (usblp->sleeping) { + count = -ENODEV; + goto done; + } + if (usblp->readurb->status) { err("usblp%d: error %d reading from printer", usblp->minor, usblp->readurb->status); @@ -1167,6 +1194,39 @@ static void usblp_disconnect(struct usb_interface *intf) mutex_unlock (&usblp_mutex); } +static int usblp_suspend (struct usb_interface *intf, pm_message_t message) +{ + struct usblp *usblp = usb_get_intfdata (intf); + + /* this races against normal access and open */ + mutex_lock (&usblp_mutex); + down (&usblp->sem); + /* we take no more IO */ + usblp->sleeping = 1; + usblp_unlink_urbs(usblp); + up (&usblp->sem); + mutex_unlock (&usblp_mutex); + + return 0; +} + +static int usblp_resume (struct usb_interface *intf) +{ + struct usblp *usblp = usb_get_intfdata (intf); + int r; + + mutex_lock (&usblp_mutex); + down (&usblp->sem); + + usblp->sleeping = 0; + r = handle_bidir (usblp); + + up (&usblp->sem); + mutex_unlock (&usblp_mutex); + + return r; +} + static struct usb_device_id usblp_ids [] = { { USB_DEVICE_INFO(7, 1, 1) }, { USB_DEVICE_INFO(7, 1, 2) }, @@ -1183,6 +1243,8 @@ static struct usb_driver usblp_driver = { .name = "usblp", .probe = usblp_probe, .disconnect = usblp_disconnect, + .suspend = usblp_suspend, + .resume = usblp_resume, .id_table = usblp_ids, }; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 724822cac2b..fed92be63b5 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1588,15 +1588,18 @@ const struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -static void usbdev_add(struct usb_device *dev) +static int usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); dev->class_dev = class_device_create(usb_device_class, NULL, MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); + if (IS_ERR(dev->class_dev)) + return PTR_ERR(dev->class_dev); dev->class_dev->class_data = dev; + return 0; } static void usbdev_remove(struct usb_device *dev) @@ -1609,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action, { switch (action) { case USB_DEVICE_ADD: - usbdev_add(dev); + if (usbdev_add(dev)) + return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: usbdev_remove(dev); diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 3ebb90149e9..3b2d137912b 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -223,7 +223,7 @@ int usb_create_ep_files(struct device *parent, ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); if (!ep_dev) { retval = -ENOMEM; - goto exit; + goto error_alloc; } /* fun calculation to determine the minor of this endpoint */ @@ -241,33 +241,31 @@ int usb_create_ep_files(struct device *parent, retval = device_register(&ep_dev->dev); if (retval) - goto error; + goto error_register; retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); if (retval) goto error_group; - endpoint->ep_dev = ep_dev; - /* create the symlink to the old-style "ep_XX" directory */ sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - retval = sysfs_create_link(&parent->kobj, - &endpoint->ep_dev->dev.kobj, name); + retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name); if (retval) goto error_link; -exit: + endpoint->ep_dev = ep_dev; return retval; error_link: sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); - error_group: device_unregister(&ep_dev->dev); - endpoint->ep_dev = NULL; destroy_endpoint_class(); return retval; -error: + +error_register: kfree(ep_dev); +error_alloc: destroy_endpoint_class(); +exit: return retval; } @@ -282,8 +280,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint) sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); device_unregister(&endpoint->ep_dev->dev); endpoint->ep_dev = NULL; + destroy_endpoint_class(); } - destroy_endpoint_class(); } - - diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 66bff184a30..ba165aff9ea 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1188,6 +1188,7 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" +static int __usb_port_suspend(struct usb_device *, int port1); #endif /** @@ -1289,8 +1290,6 @@ int usb_new_device(struct usb_device *udev) * (Includes HNP test device.) */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - static int __usb_port_suspend(struct usb_device *, - int port1); err = __usb_port_suspend(udev, udev->bus->otg_port); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index fccd1952bad..7729c074488 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -828,10 +828,7 @@ char *usb_cache_string(struct usb_device *udev, int index) * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, - * which dedicates space for this purpose. Note that several fields are - * converted to the host CPU's byte order: the USB version (bcdUSB), and - * vendors product and version fields (idVendor, idProduct, and bcdDevice). - * That lets device drivers compare against non-byteswapped constants. + * which dedicates space for this purpose. * * Not exported, only for use by the core. If drivers really want to read * the device descriptor directly, they can call usb_get_descriptor() with diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d954daa8e9e..3acc896a5d4 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1774,8 +1774,8 @@ static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL); #else -#define device_create_file(a,b) do {} while (0) -#define device_remove_file device_create_file +#define device_create_file(a,b) (0) +#define device_remove_file(a,b) do { } while (0) #endif @@ -2044,8 +2044,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - device_create_file (&dev->pdev->dev, &dev_attr_function); - device_create_file (&dev->pdev->dev, &dev_attr_queues); + retval = device_create_file (&dev->pdev->dev, &dev_attr_function); + if (retval) goto err_unbind; + retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); + if (retval) goto err_func; /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -2060,6 +2062,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) /* pci writes may still be posted */ return 0; + +err_func: + device_remove_file (&dev->pdev->dev, &dev_attr_function); +err_unbind: + driver->unbind (&dev->gadget); + dev->gadget.dev.driver = NULL; + dev->driver = NULL; + return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -2974,8 +2984,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) : "disabled"); the_controller = dev; - device_register (&dev->gadget.dev); - device_create_file (&pdev->dev, &dev_attr_registers); + retval = device_register (&dev->gadget.dev); + if (retval) goto done; + retval = device_create_file (&pdev->dev, &dev_attr_registers); + if (retval) goto done; return 0; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index f42c00ef0bc..671c24bc6d7 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -43,11 +43,11 @@ #include <linux/mm.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/irq.h> #include <asm/byteorder.h> #include <asm/dma.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/system.h> #include <asm/mach-types.h> #include <asm/unaligned.h> diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 23b95b2bfe1..34b7a31cd85 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf) } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim); + temp = scnprintf (next, size, "reclaim qh %p%s\n", + ehci->reclaim, + ehci->reclaim_ready ? " ready" : ""); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index aac6ec5dd7c..9030994aba9 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_MSECS 10 /* arbitrary */ +#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -254,7 +254,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ -static void end_unlink_async (struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" @@ -264,37 +263,25 @@ static void ehci_work(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ -static void ehci_iaa_watchdog (unsigned long param) +static void ehci_watchdog (unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; - u32 status; spin_lock_irqsave (&ehci->lock, flags); - WARN_ON(!ehci->reclaim); - /* lost IAA irqs wedge things badly; seen first with a vt8235 */ + /* lost IAA irqs wedge things badly; seen with a vt8235 */ if (ehci->reclaim) { - status = readl (&ehci->regs->status); + u32 status = readl (&ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); writel (STS_IAA, &ehci->regs->status); - end_unlink_async (ehci); + ehci->reclaim_ready = 1; } } - spin_unlock_irqrestore (&ehci->lock, flags); -} - -static void ehci_watchdog (unsigned long param) -{ - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - unsigned long flags; - - spin_lock_irqsave (&ehci->lock, flags); - - /* stop async processing after it's idled a bit */ + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) start_unlink_async (ehci, ehci->async); @@ -345,6 +332,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); + if (ehci->reclaim_ready) + end_unlink_async (ehci); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -379,7 +368,6 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); - del_timer_sync (&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -426,10 +414,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; - init_timer(&ehci->iaa_watchdog); - ehci->iaa_watchdog.function = ehci_iaa_watchdog; - ehci->iaa_watchdog.data = (unsigned long) ehci; - /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -446,6 +430,7 @@ static int ehci_init(struct usb_hcd *hcd) ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; + ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -619,7 +604,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - end_unlink_async (ehci); + ehci->reclaim_ready = 1; bh = 1; } @@ -723,14 +708,10 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - // BUG_ON(qh->qh_state != QH_STATE_LINKED); - - /* failfast */ - if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - end_unlink_async (ehci); - - /* defer till later if busy */ - else if (ehci->reclaim) { + /* if we need to use IAA and it's busy, defer */ + if (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -740,8 +721,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* start IAA cycle */ - } else + /* bypass IAA if the hc can't care */ + } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) + end_unlink_async (ehci); + + /* something else might have unlinked the qh by now */ + if (qh->qh_state == QH_STATE_LINKED) start_unlink_async (ehci, qh); } @@ -763,19 +748,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - unlink_async (ehci, qh); - break; - case QH_STATE_UNLINK: - case QH_STATE_UNLINK_WAIT: - /* already started */ - break; - case QH_STATE_IDLE: - WARN_ON(1); - break; - } + unlink_async (ehci, qh); break; case PIPE_INTERRUPT: @@ -867,7 +840,6 @@ rescan: unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ - case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2012213c0a2..1b20722c102 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = readl (&ehci->regs->command); if (ehci->reclaim) - end_unlink_async (ehci); + ehci->reclaim_ready = 1; ehci_work(ehci); /* suspend any active/unsuspended ports, maybe allow wakeup */ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 35e3fab6fc4..e51c1ed81ac 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -303,7 +303,7 @@ restart: /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - end_unlink_async (ehci); + ehci->reclaim_ready = 1; ehci_work(ehci); spin_unlock_irq(&ehci->lock); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 46327272f61..62e46dc60e8 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - iaa_watchdog_done (ehci); + timer_action_done (ehci, TIMER_IAA_WATCHDOG); // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; + ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh); @@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } + ehci->reclaim_ready = 0; cmd |= CMD_IAAD; writel (cmd, &ehci->regs->command); (void) readl (&ehci->regs->command); - iaa_watchdog_start (ehci); + timer_action (ehci, TIMER_IAA_WATCHDOG); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 6aac39f50e0..bbc3082a73d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -58,6 +58,7 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; + unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -80,7 +81,6 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ - struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -114,21 +114,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) } -static inline void -iaa_watchdog_start (struct ehci_hcd *ehci) -{ - WARN_ON(timer_pending(&ehci->iaa_watchdog)); - mod_timer (&ehci->iaa_watchdog, - jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); -} - -static inline void iaa_watchdog_done (struct ehci_hcd *ehci) -{ - del_timer (&ehci->iaa_watchdog); -} - enum ehci_timer_action { TIMER_IO_WATCHDOG, + TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -146,6 +134,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) unsigned long t; switch (action) { + case TIMER_IAA_WATCHDOG: + t = EHCI_IAA_JIFFIES; + break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -162,7 +153,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (time_before_eq(t, ehci->watchdog.expires) + if (action != TIMER_IAA_WATCHDOG + && t > ehci->watchdog.expires && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9be6b303e78..ea4714e557e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -715,13 +715,6 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) return IRQ_NOTMINE; } - if (ints & OHCI_INTR_RHSC) { - ohci_vdbg (ohci, "rhsc\n"); - ohci->next_statechange = jiffies + STATECHANGE_DELAY; - ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); - usb_hcd_poll_rh_status(hcd); - } - if (ints & OHCI_INTR_UE) { disable (ohci); ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); @@ -731,9 +724,21 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_usb_reset (ohci); } - if (ints & OHCI_INTR_RD) { - ohci_vdbg (ohci, "resume detect\n"); - ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); + if (ints & OHCI_INTR_RHSC) { + ohci_vdbg(ohci, "rhsc\n"); + ohci->next_statechange = jiffies + STATECHANGE_DELAY; + ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, + ®s->intrstatus); + usb_hcd_poll_rh_status(hcd); + } + + /* For connect and disconnect events, we expect the controller + * to turn on RHSC along with RD. But for remote wakeup events + * this might not happen. + */ + else if (ints & OHCI_INTR_RD) { + ohci_vdbg(ohci, "resume detect\n"); + ohci_writel(ohci, OHCI_INTR_RD, ®s->intrstatus); hcd->poll_rh = 1; if (ohci->autostop) { spin_lock (&ohci->lock); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 6f113596af6..6995ea36f2e 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -169,7 +169,8 @@ __acquires(ohci->lock) break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ - ohci_info (ohci, "wakeup\n"); + ohci_info(ohci, "%swakeup\n", + autostopped ? "auto-" : ""); break; case OHCI_USB_OPER: /* this can happen after resuming a swsusp snapshot */ @@ -422,7 +423,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ohci->autostop = 0; ohci->next_statechange = jiffies + STATECHANGE_DELAY; - } else if (time_after_eq (jiffies, + } else if (device_may_wakeup(&hcd->self.root_hub->dev) + && time_after_eq(jiffies, ohci->next_statechange) && !ohci->ed_rm_list && !(ohci->hc_control & diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 82cb22f002e..2dbb7741490 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -262,6 +262,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .start = ohci_pnx4008_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -280,7 +281,11 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif .start_port_reset = ohci_start_port_reset, }; @@ -410,8 +415,6 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev) goto out4; } - hcd->self.hcpriv = (void *)hcd; - pnx4008_start_hc(); platform_set_drvdata(pdev, hcd); ohci = hcd_to_ohci(hcd); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 45ee6920a85..226bf3de8ed 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -40,6 +40,7 @@ #include <linux/dma-mapping.h> #include <linux/usb.h> #include <linux/bitops.h> +#include <linux/dmi.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) return 0; } +static int remote_wakeup_is_broken(struct uhci_hcd *uhci) +{ + static struct dmi_system_id broken_wakeup_table[] = { + { + .ident = "Asus A7V8X", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"), + DMI_MATCH(DMI_BOARD_NAME, "A7V8X"), + DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"), + } + }, + { } + }; + int port; + + /* One of Asus's motherboards has a bug which causes it to + * wake up immediately from suspend-to-RAM if any of the ports + * are connected. In such cases we will not set EGSM. + */ + if (dmi_check_system(broken_wakeup_table)) { + for (port = 0; port < uhci->rh_numports; ++port) { + if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & + USBPORTSC_CCS) + return 1; + } + } + + return 0; +} + static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) __releases(uhci->lock) __acquires(uhci->lock) { int auto_stop; - int int_enable; + int int_enable, egsm_enable; auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, @@ -217,15 +248,18 @@ __acquires(uhci->lock) } /* Enable resume-detect interrupts if they work. - * Then enter Global Suspend mode, still configured. + * Then enter Global Suspend mode if _it_ works, still configured. */ + egsm_enable = USBCMD_EGSM; uhci->working_RD = 1; int_enable = USBINTR_RESUME; - if (resume_detect_interrupts_are_broken(uhci)) { + if (remote_wakeup_is_broken(uhci)) + egsm_enable = 0; + if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable) uhci->working_RD = int_enable = 0; - } + outw(int_enable, uhci->io_addr + USBINTR); - outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); + outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); mb(); udelay(5); diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 21cd2264008..20db36448ab 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -348,13 +348,3 @@ config USB_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. - -config USB_TRANCEVIBRATOR - tristate "PlayStation 2 Trance Vibrator driver support" - depends on USB - help - Say Y here if you want to connect a PlayStation 2 Trance Vibrator - device to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called trancevibrator. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 295f459d107..d946d5213b3 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -3,7 +3,7 @@ # # Multipart objects. -wacom-objs := wacom_sys.o wacom_wac.o +wacom-objs := wacom_wac.o wacom_sys.o usbhid-objs := hid-core.o # Optional parts of multipart objects. @@ -48,7 +48,6 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o -obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a6738a83ff5..6d08a3bcc95 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -270,7 +270,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign * Read data value from item. */ -static __inline__ __u32 item_udata(struct hid_item *item) +static u32 item_udata(struct hid_item *item) { switch (item->size) { case 1: return item->data.u8; @@ -280,7 +280,7 @@ static __inline__ __u32 item_udata(struct hid_item *item) return 0; } -static __inline__ __s32 item_sdata(struct hid_item *item) +static s32 item_sdata(struct hid_item *item) { switch (item->size) { case 1: return item->data.s8; @@ -727,7 +727,7 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) * done by hand. */ -static __inline__ __s32 snto32(__u32 value, unsigned n) +static s32 snto32(__u32 value, unsigned n) { switch (n) { case 8: return ((__s8)value); @@ -741,30 +741,65 @@ static __inline__ __s32 snto32(__u32 value, unsigned n) * Convert a signed 32-bit integer to a signed n-bit integer. */ -static __inline__ __u32 s32ton(__s32 value, unsigned n) +static u32 s32ton(__s32 value, unsigned n) { - __s32 a = value >> (n - 1); + s32 a = value >> (n - 1); if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; return value & ((1 << n) - 1); } /* - * Extract/implement a data field from/to a report. + * Extract/implement a data field from/to a little endian report (bit array). + * + * Code sort-of follows HID spec: + * http://www.usb.org/developers/devclass_docs/HID1_11.pdf + * + * While the USB HID spec allows unlimited length bit fields in "report + * descriptors", most devices never use more than 16 bits. + * One model of UPS is claimed to report "LINEV" as a 32-bit field. + * Search linux-kernel and linux-usb-devel archives for "hid-core extract". */ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { - report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1); + u64 x; + + WARN_ON(n > 32); + + report += offset >> 3; /* adjust byte index */ + offset &= 7; /* now only need bit offset into one byte */ + x = get_unaligned((u64 *) report); + x = le64_to_cpu(x); + x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ + return (u32) x; } +/* + * "implement" : set bits in a little endian bit stream. + * Same concepts as "extract" (see comments above). + * The data mangled in the bit stream remains in little endian + * order the whole time. It make more sense to talk about + * endianness of register values by considering a register + * a "cached" copy of the little endiad bit stream. + */ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) { - report += (offset >> 5) << 2; offset &= 31; - put_unaligned((get_unaligned((__le64*)report) - & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) - | cpu_to_le64((__u64)value << offset), (__le64*)report); + u64 x; + u64 m = (1ULL << n) - 1; + + WARN_ON(n > 32); + + WARN_ON(value > m); + value &= m; + + report += offset >> 3; + offset &= 7; + + x = get_unaligned((u64 *)report); + x &= cpu_to_le64(~(m << offset)); + x |= cpu_to_le64(((u64) value) << offset); + put_unaligned(x, (u64 *) report); } /* @@ -1381,6 +1416,9 @@ void hid_close(struct hid_device *hid) #define USB_VENDOR_ID_PANJIT 0x134c +#define USB_VENDOR_ID_TURBOX 0x062a +#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 + /* * Initialize all reports */ @@ -1602,6 +1640,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab +#define USB_VENDOR_ID_AIRCABLE 0x16CA +#define USB_DEVICE_ID_AIRCABLE1 0x1502 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -1619,6 +1660,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, @@ -1755,11 +1797,12 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, 0x0219, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, 0x021B, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, @@ -1768,6 +1811,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, + { 0, 0 } }; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 9a808a3b4d3..68e7ebb978a 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -121,6 +121,12 @@ static struct hidinput_key_translation powerbook_numlock_keys[] = { { } }; +static struct hidinput_key_translation powerbook_iso_keyboard[] = { + { KEY_GRAVE, KEY_102ND }, + { KEY_102ND, KEY_GRAVE }, + { } +}; + static int usbhid_pb_fnmode = 1; module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); MODULE_PARM_DESC(pb_fnmode, @@ -195,6 +201,14 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, } } + if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { + trans = find_translation(powerbook_iso_keyboard, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } + } + return 0; } @@ -210,6 +224,9 @@ static void hidinput_pb_setup(struct input_dev *input) for (trans = powerbook_numlock_keys; trans->from; trans++) set_bit(trans->to, input->keybit); + + for (trans = powerbook_iso_keyboard; trans->from; trans++) + set_bit(trans->to, input->keybit); } #else static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 9b50effef75..0e76e6dcac3 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -260,6 +260,7 @@ struct hid_item { #define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 #define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 #define HID_QUIRK_INVERT_HWHEEL 0x00004000 +#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 /* * This is the global environment of the parser. This information is diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index f26c1cd1129..933ceddf3de 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -256,10 +256,10 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr { *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); - *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F); + *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); *touch = ~pkt[7] & 0x20; - return 1; + return *touch; } #endif @@ -640,7 +640,7 @@ static int usbtouch_probe(struct usb_interface *intf, type->max_press, 0, 0); usb_fill_int_urb(usbtouch->irq, usbtouch->udev, - usb_rcvintpipe(usbtouch->udev, 0x81), + usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch, endpoint->bInterval); diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h index 7b3840e378a..1cf08f02c50 100644 --- a/drivers/usb/input/wacom.h +++ b/drivers/usb/input/wacom.h @@ -63,6 +63,7 @@ * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, * - where wacom_sys.c deals with system specific code, * - and wacom_wac.c deals with Wacom specific code + * - Support Intuos3 4x6 */ /* @@ -118,6 +119,7 @@ extern void wacom_input_sync(void *wcombo); extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index d233c37bd53..3498b893b53 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -110,7 +110,7 @@ __u16 wacom_be16_to_cpu(unsigned char *data) __u16 wacom_le16_to_cpu(unsigned char *data) { __u16 value; - value = be16_to_cpu(*(__be16 *) data); + value = le16_to_cpu(*(__le16 *) data); return value; } @@ -143,7 +143,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_dev->evbit[0] |= BIT(EV_MSC); input_dev->mscbit[0] |= BIT(MSC_SERIAL); input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4); } void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -155,11 +155,16 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); } -void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); +} + +void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); } @@ -218,8 +223,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom_wac->features = get_wacom_feature(id); - if (wacom_wac->features->pktlen > 10) - BUG(); + BUG_ON(wacom_wac->features->pktlen > 10); input_dev->name = wacom_wac->features->name; wacom->wacom_wac = wacom_wac; @@ -244,7 +248,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom_wac->data, wacom_wac->features->pktlen, - wacom_wac->features->irq, wacom, endpoint->bInterval); + wacom_sys_irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -278,8 +282,8 @@ static void wacom_disconnect(struct usb_interface *intf) input_unregister_device(wacom->dev); usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma); - kfree(wacom); kfree(wacom->wacom_wac); + kfree(wacom); } } diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index aa31d22d4f0..92726fe8937 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -191,9 +191,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); if (wacom->features->type == WACOM_G4) - wacom_report_abs(wcombo, ABS_DISTANCE, data[6]); + wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); else - wacom_report_abs(wcombo, ABS_DISTANCE, data[7]); + wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); break; } } @@ -303,8 +303,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom->tool[idx] = BTN_TOOL_PEN; } /* only large I3 support Lens Cursor */ - if(!((wacom->tool[idx] == BTN_TOOL_LENS) && - (wacom->features->type == INTUOS3))) { + if(!((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S)))) { wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ wacom_report_key(wcombo, wacom->tool[idx], 1); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); @@ -315,10 +316,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { - wacom_report_key(wcombo, wacom->tool[idx], 0); - wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - return 2; + if(!((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S)))) { + wacom_report_key(wcombo, wacom->tool[idx], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + return 2; + } } return 0; } @@ -382,7 +387,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); - if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2]) + if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | + data[2] | (data[3] & 0x1f) | data[4]) wacom_report_key(wcombo, wacom->tool[1], 1); else wacom_report_key(wcombo, wacom->tool[1], 0); @@ -432,7 +438,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) ((t - 1) / 2) : -t / 2); } - } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) { + } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) { /* 4D mouse packet */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -452,12 +458,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) - ((data[8] & 0x02) >> 1)); /* I3 2D mouse side buttons */ - if (wacom->features->type == INTUOS3) { + if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); } - } else if (wacom->features->type < INTUOS3) { + } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) { /* Lens cursor packets */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -490,6 +496,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) return (wacom_ptu_irq(wacom_wac, wcombo)); break; case INTUOS: + case INTUOS3S: case INTUOS3: case INTUOS3L: case CINTIQ: @@ -515,6 +522,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w case CINTIQ: input_dev_i3(input_dev, wacom_wac); /* fall through */ + case INTUOS3S: + input_dev_i3s(input_dev, wacom_wac); case INTUOS: input_dev_i(input_dev, wacom_wac); break; @@ -530,49 +539,50 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w } static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_sys_irq }, - { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_sys_irq }, - { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_sys_irq }, - { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq}, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq}, - { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_sys_irq }, - { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PTU, wacom_sys_irq }, - { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, - { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, - { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_sys_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, + { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER }, + { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE }, + { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE }, + { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, + { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, + { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, + { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE }, + { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE }, + { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE }, + { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom PL400", 8, 5408, 4056, 255, 0, PL }, + { "Wacom PL500", 8, 6144, 4608, 255, 0, PL }, + { "Wacom PL600", 8, 6126, 4604, 255, 0, PL }, + { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL }, + { "Wacom PL550", 8, 6144, 4608, 511, 0, PL }, + { "Wacom PL800", 8, 7220, 5780, 511, 0, PL }, + { "Wacom PL700", 8, 6758, 5406, 511, 0, PL }, + { "Wacom PL510", 8, 6282, 4762, 511, 0, PL }, + { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL }, + { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL }, + { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL }, + { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S }, + { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S }, + { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { } }; @@ -618,6 +628,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h index ceae7bf59d9..a1d9ce00797 100644 --- a/drivers/usb/input/wacom_wac.h +++ b/drivers/usb/input/wacom_wac.h @@ -20,6 +20,7 @@ enum { PTU, PL, INTUOS, + INTUOS3S, INTUOS3, INTUOS3L, CINTIQ, @@ -34,7 +35,6 @@ struct wacom_features { int pressure_max; int distance_max; int type; - usb_complete_t irq; }; struct wacom_wac { diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index cebb6c463bf..df97e5c803f 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -1,8 +1,13 @@ /* - * X-Box gamepad - v0.0.5 + * X-Box gamepad - v0.0.6 * * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> - * + * 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>, + * Steven Toth <steve@toth.demon.co.uk>, + * Franz Lehner <franz@caos.at>, + * Ivan Hawkes <blackhawk@ivanhawkes.com> + * 2005 Dominic Cerquetti <binary1230@yahoo.com> + * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,11 +33,13 @@ * - ITO Takayuki for providing essential xpad information on his website * - Vojtech Pavlik - iforce driver / input subsystem * - Greg Kroah-Hartman - usb-skeleton driver + * - XBOX Linux project - extra USB id's * * TODO: - * - fine tune axes + * - fine tune axes (especially trigger axes) * - fix "analog" buttons (reported as digital now) * - get rumble working + * - need USB IDs for other dance pads * * History: * @@ -52,30 +59,79 @@ * - fixed d-pad to axes mapping * * 2002-07-17 - 0.0.5 : simplified d-pad handling + * + * 2004-10-02 - 0.0.6 : DDR pad support + * - borrowed from the XBOX linux kernel + * - USB id's for commonly used dance pads are present + * - dance pads will map D-PAD to buttons, not axes + * - pass the module paramater 'dpad_to_buttons' to force + * the D-PAD to map to buttons if your pad is not detected */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/smp_lock.h> #include <linux/usb/input.h> -#define DRIVER_VERSION "v0.0.5" +#define DRIVER_VERSION "v0.0.6" #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" #define DRIVER_DESC "X-Box pad driver" #define XPAD_PKT_LEN 32 +/* xbox d-pads should map to buttons, as is required for DDR pads + but we map them to axes when possible to simplify things */ +#define MAP_DPAD_TO_BUTTONS 0 +#define MAP_DPAD_TO_AXES 1 +#define MAP_DPAD_UNKNOWN -1 + +static int dpad_to_buttons; +module_param(dpad_to_buttons, bool, S_IRUGO); +MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); + static const struct xpad_device { u16 idVendor; u16 idProduct; char *name; + u8 dpad_mapping; } xpad_device[] = { - { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, - { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, - { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, - { 0x0000, 0x0000, "X-Box pad" } + { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS }, + { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES }, + { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES }, + { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES }, + { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES }, + { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS }, + { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS }, + { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES }, + { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES }, + { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES}, + { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES }, + { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES }, + { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES }, + { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES }, + { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS }, + { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS }, + { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES }, + { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN } }; static const signed short xpad_btn[] = { @@ -84,11 +140,23 @@ static const signed short xpad_btn[] = { -1 /* terminating entry */ }; +/* only used if MAP_DPAD_TO_BUTTONS */ +static const signed short xpad_btn_pad[] = { + BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ + BTN_0, BTN_1, /* d-pad up, down (XXX names??) */ + -1 /* terminating entry */ +}; + static const signed short xpad_abs[] = { ABS_X, ABS_Y, /* left stick */ ABS_RX, ABS_RY, /* right stick */ ABS_Z, ABS_RZ, /* triggers left/right */ - ABS_HAT0X, ABS_HAT0Y, /* digital pad */ + -1 /* terminating entry */ +}; + +/* only used if MAP_DPAD_TO_AXES */ +static const signed short xpad_abs_pad[] = { + ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */ -1 /* terminating entry */ }; @@ -100,14 +168,16 @@ static struct usb_device_id xpad_table [] = { MODULE_DEVICE_TABLE (usb, xpad_table); struct usb_xpad { - struct input_dev *dev; /* input device interface */ - struct usb_device *udev; /* usb device */ + struct input_dev *dev; /* input device interface */ + struct usb_device *udev; /* usb device */ - struct urb *irq_in; /* urb for interrupt in report */ - unsigned char *idata; /* input data */ + struct urb *irq_in; /* urb for interrupt in report */ + unsigned char *idata; /* input data */ dma_addr_t idata_dma; - char phys[65]; /* physical device path */ + char phys[65]; /* physical device path */ + + int dpad_mapping; /* map d-pad to buttons or to axes */ }; /* @@ -137,14 +207,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_abs(dev, ABS_RZ, data[11]); /* digital pad */ - input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { + input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { + input_report_key(dev, BTN_LEFT, data[2] & 0x04); + input_report_key(dev, BTN_RIGHT, data[2] & 0x08); + input_report_key(dev, BTN_0, data[2] & 0x01); // up + input_report_key(dev, BTN_1, data[2] & 0x02); // down + } /* start/back buttons and stick press left/right */ - input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); - input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); - input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); - input_report_key(dev, BTN_THUMBR, data[2] >> 7); + input_report_key(dev, BTN_START, data[2] & 0x10); + input_report_key(dev, BTN_BACK, data[2] & 0x20); + input_report_key(dev, BTN_THUMBL, data[2] & 0x40); + input_report_key(dev, BTN_THUMBR, data[2] & 0x80); /* "analog" buttons A, B, X, Y */ input_report_key(dev, BTN_A, data[4]); @@ -206,6 +283,28 @@ static void xpad_close (struct input_dev *dev) usb_kill_urb(xpad->irq_in); } +static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) +{ + set_bit(abs, input_dev->absbit); + + switch (abs) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); + break; + case ABS_Z: + case ABS_RZ: /* the triggers */ + input_set_abs_params(input_dev, abs, 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */ + input_set_abs_params(input_dev, abs, -1, 1, 0, 0); + break; + } +} + static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev (intf); @@ -235,6 +334,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail2; xpad->udev = udev; + xpad->dpad_mapping = xpad_device[i].dpad_mapping; + if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) + xpad->dpad_mapping = dpad_to_buttons; xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -249,32 +351,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + /* set up buttons */ for (i = 0; xpad_btn[i] >= 0; i++) set_bit(xpad_btn[i], input_dev->keybit); + if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) + for (i = 0; xpad_btn_pad[i] >= 0; i++) + set_bit(xpad_btn_pad[i], input_dev->keybit); - for (i = 0; xpad_abs[i] >= 0; i++) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, -32768, 32767, 16, 128); - break; - case ABS_Z: - case ABS_RZ: /* the triggers */ - input_set_abs_params(input_dev, t, 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, -1, 1, 0, 0); - break; - } - } + /* set up axes */ + for (i = 0; xpad_abs[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs[i]); + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) + for (i = 0; xpad_abs_pad[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs_pad[i]); ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(xpad->irq_in, udev, @@ -305,7 +394,8 @@ static void xpad_disconnect(struct usb_interface *intf) usb_kill_urb(xpad->irq_in); input_unregister_device(xpad->dev); usb_free_urb(xpad->irq_in); - usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); + usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, + xpad->idata, xpad->idata_dma); kfree(xpad); } } diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c29658f69e2..a74bf8617e7 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -223,6 +223,16 @@ config USB_LD To compile this driver as a module, choose M here: the module will be called ldusb. +config USB_TRANCEVIBRATOR + tristate "PlayStation 2 Trance Vibrator driver support" + depends on USB + help + Say Y here if you want to connect a PlayStation 2 Trance Vibrator + device to your computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called trancevibrator. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2be70fa259b..11dc59540cd 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_TEST) += usbtest.o +obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index aecd633fe9f..af2934e016a 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -370,7 +370,8 @@ static int adu_release(struct inode *inode, struct file *file) retval = adu_release_internal(dev); exit: - up(&dev->sem); + if (dev) + up(&dev->sem); dbg(2," %s : leave, return value %d", __FUNCTION__, retval); return retval; } diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 0be9d62d62a..e4971d6aaaf 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -780,7 +780,7 @@ static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned bl_fail:/* not enough memory. Free allocated elements */ dbg ("auerbuf_setup: no more memory"); - kfree(bep); + auerbuf_free(bep); auerbuf_free_buffers (bcp); return -ENOMEM; } diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 0eb26a26115..9b591b8b936 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -513,8 +513,6 @@ static void ftdi_elan_respond_work(void *data) ftdi->disconnected += 1; } else if (retval == -ENODEV) { ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; } else if (retval == -EILSEQ) { ftdi->disconnected += 1; } else { @@ -1186,11 +1184,8 @@ static ssize_t ftdi_elan_write(struct file *file, int retval = 0; struct urb *urb; char *buf; - char data[30 *3 + 4]; - char *d = data; - const char __user *s = user_buffer; - int m = (sizeof(data) - 1) / 3; - struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; + struct usb_ftdi *ftdi = file->private_data; + if (ftdi->disconnected > 0) { return -ENODEV; } @@ -1220,27 +1215,18 @@ static ssize_t ftdi_elan_write(struct file *file, if (retval) { dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" "d\n", retval); - goto error_4; + goto error_3; } usb_free_urb(urb); - exit:; - if (count > m) { - int I = m - 1; - while (I-- > 0) { - d += sprintf(d, " %02X", 0x000000FF & *s++); - } - d += sprintf(d, " .."); - } else { - int I = count; - while (I-- > 0) { - d += sprintf(d, " %02X", 0x000000FF & *s++); - } - } + +exit: return count; - error_4: error_3:usb_buffer_free(ftdi->udev, count, buf, - urb->transfer_dma); - error_2:usb_free_urb(urb); - error_1:return retval; +error_3: + usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma); +error_2: + usb_free_urb(urb); +error_1: + return retval; } static struct file_operations ftdi_elan_fops = { diff --git a/drivers/usb/input/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 33cd91d11ec..33cd91d11ec 100644 --- a/drivers/usb/input/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 054059632a2..e081836014a 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -92,8 +92,13 @@ config USB_RTL8150 To compile this driver as a module, choose M here: the module will be called rtl8150. +config USB_USBNET_MII + tristate + default n + config USB_USBNET tristate "Multi-purpose USB Networking Framework" + select MII if USBNET_MII != n ---help--- This driver supports several kinds of network links over USB, with "minidrivers" built around a common network driver core @@ -129,7 +134,7 @@ config USB_NET_AX8817X tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" depends on USB_USBNET && NET_ETHERNET select CRC32 - select MII + select USB_USBNET_MII default y help This option adds support for ASIX AX88xxx based USB 2.0 @@ -207,6 +212,15 @@ config USB_NET_PLUSB Choose this option if you're using a host-to-host cable with one of these chips. +config USB_NET_MCS7830 + tristate "MosChip MCS7830 based Ethernet adapters" + depends on USB_USBNET + select USB_USBNET_MII + help + Choose this option if you're using a 10/100 Ethernet USB2 + adapter based on the MosChip 7830 controller. This includes + adapters marketed under the DeLOCK brand. + config USB_NET_RNDIS_HOST tristate "Host for RNDIS devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 160f19dbdf1..7b51964de17 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o +obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o ifeq ($(CONFIG_USB_DEBUG),y) diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index c73dd224aa7..881841e600d 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -569,10 +569,12 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) struct usbnet *dev = netdev_priv(netdev); u16 res; + mutex_lock(&dev->phy_mutex); asix_set_sw_mii(dev); asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); asix_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); @@ -586,10 +588,12 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) u16 res = cpu_to_le16(val); devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); + mutex_lock(&dev->phy_mutex); asix_set_sw_mii(dev); asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); asix_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); } /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ @@ -700,32 +704,6 @@ static void asix_get_drvinfo (struct net_device *net, info->eedump_len = data->eeprom_len; } -static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_gset(&dev->mii,cmd); -} - -static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - int res = mii_ethtool_sset(&dev->mii,cmd); - - /* link speed/duplex might have changed */ - if (dev->driver_info->link_reset) - dev->driver_info->link_reset(dev); - - return res; -} - -static int asix_nway_reset(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_nway_restart(&dev->mii); -} - static u32 asix_get_link(struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -746,15 +724,15 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) static struct ethtool_ops ax88172_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static void ax88172_set_multicast(struct net_device *net) @@ -885,15 +863,15 @@ out1: static struct ethtool_ops ax88772_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int ax88772_link_reset(struct usbnet *dev) @@ -1046,15 +1024,15 @@ out1: static struct ethtool_ops ax88178_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int marvell_phy_init(struct usbnet *dev) diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 82ce0358d9a..f6971b88349 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = { static int __init cdc_init(void) { - BUG_ON((sizeof(((struct usbnet *)0)->data) + BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct cdc_state))); return usb_register(&cdc_driver); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 957d4ad316f..7c906a43e49 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -65,16 +65,6 @@ #undef DEBUG -#ifdef DEBUG -#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) -#else -#define kaweth_dbg(format, arg...) do {} while (0) -#endif -#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg) -#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg) -#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg) - - #include "kawethfw.h" #define KAWETH_MTU 1514 @@ -86,6 +76,9 @@ #define KAWETH_STATUS_BROKEN 0x0000001 #define KAWETH_STATUS_CLOSING 0x0000002 +#define KAWETH_STATUS_SUSPENDING 0x0000004 + +#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 @@ -112,6 +105,8 @@ #define STATE_MASK 0x40 #define STATE_SHIFT 5 +#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) + MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); @@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout); +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); +static int kaweth_resume(struct usb_interface *intf); /**************************************************************** * usb_device_id @@ -179,6 +176,8 @@ static struct usb_driver kaweth_driver = { .name = driver_name, .probe = kaweth_probe, .disconnect = kaweth_disconnect, + .suspend = kaweth_suspend, + .resume = kaweth_resume, .id_table = usb_klsi_table, }; @@ -222,6 +221,7 @@ struct kaweth_device int suspend_lowmem_rx; int suspend_lowmem_ctrl; int linkstate; + int opened; struct work_struct lowmem_work; struct usb_device *dev; @@ -265,17 +265,17 @@ static int kaweth_control(struct kaweth_device *kaweth, { struct usb_ctrlrequest *dr; - kaweth_dbg("kaweth_control()"); + dbg("kaweth_control()"); if(in_interrupt()) { - kaweth_dbg("in_interrupt()"); + dbg("in_interrupt()"); return -EBUSY; } dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); if (!dr) { - kaweth_dbg("kmalloc() failed"); + dbg("kmalloc() failed"); return -ENOMEM; } @@ -300,7 +300,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth) { int retval; - kaweth_dbg("Reading kaweth configuration"); + dbg("Reading kaweth configuration"); retval = kaweth_control(kaweth, usb_rcvctrlpipe(kaweth->dev, 0), @@ -322,7 +322,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) { int retval; - kaweth_dbg("Setting URB size to %d", (unsigned)urb_size); + dbg("Setting URB size to %d", (unsigned)urb_size); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -344,7 +344,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) { int retval; - kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait); + dbg("Set SOFS wait to %d", (unsigned)sofs_wait); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -367,7 +367,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth, { int retval; - kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter); + dbg("Set receive filter to %d", (unsigned)receive_filter); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -392,7 +392,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, __u8 type) { if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { - kaweth_err("Firmware too big: %d", data_len); + err("Firmware too big: %d", data_len); return -ENOSPC; } @@ -403,13 +403,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, kaweth->firmware_buf[4] = type; kaweth->firmware_buf[5] = interrupt; - kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3], + dbg("High: %i, Low:%i", kaweth->firmware_buf[3], kaweth->firmware_buf[2]); - kaweth_dbg("Downloading firmware at %p to kaweth device at %p", + dbg("Downloading firmware at %p to kaweth device at %p", data, kaweth); - kaweth_dbg("Firmware length: %d", data_len); + dbg("Firmware length: %d", data_len); return kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -437,7 +437,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth, kaweth->firmware_buf[6] = 0x00; kaweth->firmware_buf[7] = 0x00; - kaweth_dbg("Triggering firmware"); + dbg("Triggering firmware"); return kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -457,7 +457,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) { int result; - kaweth_dbg("kaweth_reset(%p)", kaweth); + dbg("kaweth_reset(%p)", kaweth); result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), USB_REQ_SET_CONFIGURATION, @@ -470,7 +470,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) mdelay(10); - kaweth_dbg("kaweth_reset() returns %d.",result); + dbg("kaweth_reset() returns %d.",result); return result; } @@ -534,7 +534,7 @@ static void kaweth_resubmit_tl(void *d) { struct kaweth_device *kaweth = (struct kaweth_device *)d; - if (kaweth->status | KAWETH_STATUS_CLOSING) + if (IS_BLOCKED(kaweth->status)) return; if (kaweth->suspend_lowmem_rx) @@ -568,7 +568,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, kaweth->suspend_lowmem_rx = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } - kaweth_err("resubmitting rx_urb %d failed", result); + err("resubmitting rx_urb %d failed", result); } else { kaweth->suspend_lowmem_rx = 0; } @@ -601,11 +601,15 @@ static void kaweth_usb_receive(struct urb *urb) return; } - if (kaweth->status & KAWETH_STATUS_CLOSING) + spin_lock(&kaweth->device_lock); + if (IS_BLOCKED(kaweth->status)) { + spin_unlock(&kaweth->device_lock); return; + } + spin_unlock(&kaweth->device_lock); if(urb->status && urb->status != -EREMOTEIO && count != 1) { - kaweth_err("%s RX status: %d count: %d packet_len: %d", + err("%s RX status: %d count: %d packet_len: %d", net->name, urb->status, count, @@ -616,9 +620,9 @@ static void kaweth_usb_receive(struct urb *urb) if(kaweth->net && (count > 2)) { if(pkt_len > (count - 2)) { - kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); - kaweth_err("Packet len & 2047: %x", pkt_len & 2047); - kaweth_err("Count 2: %x", count2); + err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); + err("Packet len & 2047: %x", pkt_len & 2047); + err("Count 2: %x", count2); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } @@ -655,7 +659,7 @@ static int kaweth_open(struct net_device *net) struct kaweth_device *kaweth = netdev_priv(net); int res; - kaweth_dbg("Opening network device."); + dbg("Opening network device."); res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) @@ -678,6 +682,7 @@ static int kaweth_open(struct net_device *net) usb_kill_urb(kaweth->rx_urb); return -EIO; } + kaweth->opened = 1; netif_start_queue(net); @@ -688,14 +693,8 @@ static int kaweth_open(struct net_device *net) /**************************************************************** * kaweth_close ****************************************************************/ -static int kaweth_close(struct net_device *net) +static void kaweth_kill_urbs(struct kaweth_device *kaweth) { - struct kaweth_device *kaweth = netdev_priv(net); - - netif_stop_queue(net); - - kaweth->status |= KAWETH_STATUS_CLOSING; - usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); @@ -706,6 +705,21 @@ static int kaweth_close(struct net_device *net) we hit them again */ usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); +} + +/**************************************************************** + * kaweth_close + ****************************************************************/ +static int kaweth_close(struct net_device *net) +{ + struct kaweth_device *kaweth = netdev_priv(net); + + netif_stop_queue(net); + kaweth->opened = 0; + + kaweth->status |= KAWETH_STATUS_CLOSING; + + kaweth_kill_urbs(kaweth); kaweth->status &= ~KAWETH_STATUS_CLOSING; @@ -732,7 +746,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb) if (unlikely(urb->status != 0)) if (urb->status != -ENOENT) - kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); + dbg("%s: TX status %d.", kaweth->net->name, urb->status); netif_wake_queue(kaweth->net); dev_kfree_skb_irq(skb); @@ -752,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth_async_set_rx_mode(kaweth); netif_stop_queue(net); + if (IS_BLOCKED(kaweth->status)) { + goto skip; + } /* We now decide whether we can put our special header into the sk_buff */ if (skb_cloned(skb) || skb_headroom(skb) < 2) { @@ -783,7 +800,8 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { - kaweth_warn("kaweth failed tx_urb %d", res); + warn("kaweth failed tx_urb %d", res); +skip: kaweth->stats.tx_errors++; netif_start_queue(net); @@ -812,7 +830,7 @@ static void kaweth_set_rx_mode(struct net_device *net) KAWETH_PACKET_FILTER_BROADCAST | KAWETH_PACKET_FILTER_MULTICAST; - kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap); + dbg("Setting Rx mode to %d", packet_filter_bitmap); netif_stop_queue(net); @@ -850,10 +868,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) KAWETH_CONTROL_TIMEOUT); if(result < 0) { - kaweth_err("Failed to set Rx mode: %d", result); + err("Failed to set Rx mode: %d", result); } else { - kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap); + dbg("Set Rx mode to %d", packet_filter_bitmap); } } } @@ -874,7 +892,7 @@ static void kaweth_tx_timeout(struct net_device *net) { struct kaweth_device *kaweth = netdev_priv(net); - kaweth_warn("%s: Tx timed out. Resetting.", net->name); + warn("%s: Tx timed out. Resetting.", net->name); kaweth->stats.tx_errors++; net->trans_start = jiffies; @@ -882,6 +900,42 @@ static void kaweth_tx_timeout(struct net_device *net) } /**************************************************************** + * kaweth_suspend + ****************************************************************/ +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct kaweth_device *kaweth = usb_get_intfdata(intf); + unsigned long flags; + + spin_lock_irqsave(&kaweth->device_lock, flags); + kaweth->status |= KAWETH_STATUS_SUSPENDING; + spin_unlock_irqrestore(&kaweth->device_lock, flags); + + kaweth_kill_urbs(kaweth); + return 0; +} + +/**************************************************************** + * kaweth_resume + ****************************************************************/ +static int kaweth_resume(struct usb_interface *intf) +{ + struct kaweth_device *kaweth = usb_get_intfdata(intf); + unsigned long flags; + + spin_lock_irqsave(&kaweth->device_lock, flags); + kaweth->status &= ~KAWETH_STATUS_SUSPENDING; + spin_unlock_irqrestore(&kaweth->device_lock, flags); + + if (!kaweth->opened) + return 0; + kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); + kaweth_resubmit_int_urb(kaweth, GFP_NOIO); + + return 0; +} + +/**************************************************************** * kaweth_probe ****************************************************************/ static int kaweth_probe( @@ -895,15 +949,15 @@ static int kaweth_probe( const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; int result = 0; - kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", + dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", dev->devnum, le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct), le16_to_cpu(dev->descriptor.bcdDevice)); - kaweth_dbg("Device at %p", dev); + dbg("Device at %p", dev); - kaweth_dbg("Descriptor length: %x type: %x", + dbg("Descriptor length: %x type: %x", (int)dev->descriptor.bLength, (int)dev->descriptor.bDescriptorType); @@ -918,7 +972,7 @@ static int kaweth_probe( spin_lock_init(&kaweth->device_lock); init_waitqueue_head(&kaweth->term_wait); - kaweth_dbg("Resetting."); + dbg("Resetting."); kaweth_reset(kaweth); @@ -928,17 +982,17 @@ static int kaweth_probe( */ if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { - kaweth_info("Firmware present in device."); + info("Firmware present in device."); } else { /* Download the firmware */ - kaweth_info("Downloading firmware..."); + info("Downloading firmware..."); kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); if ((result = kaweth_download_firmware(kaweth, kaweth_new_code, len_kaweth_new_code, 100, 2)) < 0) { - kaweth_err("Error downloading firmware (%d)", result); + err("Error downloading firmware (%d)", result); goto err_fw; } @@ -947,7 +1001,7 @@ static int kaweth_probe( len_kaweth_new_code_fix, 100, 3)) < 0) { - kaweth_err("Error downloading firmware fix (%d)", result); + err("Error downloading firmware fix (%d)", result); goto err_fw; } @@ -956,7 +1010,7 @@ static int kaweth_probe( len_kaweth_trigger_code, 126, 2)) < 0) { - kaweth_err("Error downloading trigger code (%d)", result); + err("Error downloading trigger code (%d)", result); goto err_fw; } @@ -966,18 +1020,18 @@ static int kaweth_probe( len_kaweth_trigger_code_fix, 126, 3)) < 0) { - kaweth_err("Error downloading trigger code fix (%d)", result); + err("Error downloading trigger code fix (%d)", result); goto err_fw; } if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { - kaweth_err("Error triggering firmware (%d)", result); + err("Error triggering firmware (%d)", result); goto err_fw; } /* Device will now disappear for a moment... */ - kaweth_info("Firmware loaded. I'll be back..."); + info("Firmware loaded. I'll be back..."); err_fw: free_page((unsigned long)kaweth->firmware_buf); free_netdev(netdev); @@ -987,14 +1041,14 @@ err_fw: result = kaweth_read_configuration(kaweth); if(result < 0) { - kaweth_err("Error reading configuration (%d), no net device created", result); + err("Error reading configuration (%d), no net device created", result); goto err_free_netdev; } - kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask); - kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); - kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); - kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + info("Statistics collection: %x", kaweth->configuration.statistics_mask); + info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); + info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); + info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", (int)kaweth->configuration.hw_addr[0], (int)kaweth->configuration.hw_addr[1], (int)kaweth->configuration.hw_addr[2], @@ -1005,17 +1059,17 @@ err_fw: if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr))) { - kaweth_err("Firmware not functioning properly, no net device created"); + err("Firmware not functioning properly, no net device created"); goto err_free_netdev; } if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { - kaweth_dbg("Error setting URB size"); + dbg("Error setting URB size"); goto err_free_netdev; } if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { - kaweth_err("Error setting SOFS wait"); + err("Error setting SOFS wait"); goto err_free_netdev; } @@ -1025,11 +1079,11 @@ err_fw: KAWETH_PACKET_FILTER_MULTICAST); if(result < 0) { - kaweth_err("Error setting receive filter"); + err("Error setting receive filter"); goto err_free_netdev; } - kaweth_dbg("Initializing net device."); + dbg("Initializing net device."); kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kaweth->tx_urb) @@ -1086,13 +1140,13 @@ err_fw: SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - kaweth_err("Error registering netdev."); + err("Error registering netdev."); goto err_intfdata; } - kaweth_info("kaweth interface created at %s", kaweth->net->name); + info("kaweth interface created at %s", kaweth->net->name); - kaweth_dbg("Kaweth probe returning."); + dbg("Kaweth probe returning."); return 0; @@ -1121,16 +1175,16 @@ static void kaweth_disconnect(struct usb_interface *intf) struct kaweth_device *kaweth = usb_get_intfdata(intf); struct net_device *netdev; - kaweth_info("Unregistering"); + info("Unregistering"); usb_set_intfdata(intf, NULL); if (!kaweth) { - kaweth_warn("unregistering non-existant device"); + warn("unregistering non-existant device"); return; } netdev = kaweth->net; - kaweth_dbg("Unregistering net device"); + dbg("Unregistering net device"); unregister_netdev(netdev); usb_free_urb(kaweth->rx_urb); @@ -1185,7 +1239,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { // timeout - kaweth_warn("usb_control/bulk_msg: timeout"); + warn("usb_control/bulk_msg: timeout"); usb_kill_urb(urb); // remove urb safely status = -ETIMEDOUT; } @@ -1234,7 +1288,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, ****************************************************************/ static int __init kaweth_init(void) { - kaweth_dbg("Driver loading"); + dbg("Driver loading"); return usb_register(&kaweth_driver); } diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c new file mode 100644 index 00000000000..6240b978fe3 --- /dev/null +++ b/drivers/usb/net/mcs7830.c @@ -0,0 +1,534 @@ +/* + * MosChips MCS7830 based USB 2.0 Ethernet Devices + * + * based on usbnet.c, asix.c and the vendor provided mcs7830 driver + * + * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de> + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> + * Copyright (c) 2002-2003 TiVo 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/crc32.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/init.h> +#include <linux/mii.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include "usbnet.h" + +/* requests */ +#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ + USB_RECIP_DEVICE) +#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ + USB_RECIP_DEVICE) +#define MCS7830_RD_BREQ 0x0E +#define MCS7830_WR_BREQ 0x0D + +#define MCS7830_CTRL_TIMEOUT 1000 +#define MCS7830_MAX_MCAST 64 + +#define MCS7830_VENDOR_ID 0x9710 +#define MCS7830_PRODUCT_ID 0x7830 + +#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ + ADVERTISE_100HALF | ADVERTISE_10FULL | \ + ADVERTISE_10HALF | ADVERTISE_CSMA) + +/* HIF_REG_XX coressponding index value */ +enum { + HIF_REG_MULTICAST_HASH = 0x00, + HIF_REG_PACKET_GAP1 = 0x08, + HIF_REG_PACKET_GAP2 = 0x09, + HIF_REG_PHY_DATA = 0x0a, + HIF_REG_PHY_CMD1 = 0x0c, + HIF_REG_PHY_CMD1_READ = 0x40, + HIF_REG_PHY_CMD1_WRITE = 0x20, + HIF_REG_PHY_CMD1_PHYADDR = 0x01, + HIF_REG_PHY_CMD2 = 0x0d, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, + HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, + HIF_REG_CONFIG = 0x0e, + HIF_REG_CONFIG_CFG = 0x80, + HIF_REG_CONFIG_SPEED100 = 0x40, + HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, + HIF_REG_CONFIG_RXENABLE = 0x10, + HIF_REG_CONFIG_TXENABLE = 0x08, + HIF_REG_CONFIG_SLEEPMODE = 0x04, + HIF_REG_CONFIG_ALLMULTICAST = 0x02, + HIF_REG_CONFIG_PROMISCIOUS = 0x01, + HIF_REG_ETHERNET_ADDR = 0x0f, + HIF_REG_22 = 0x15, + HIF_REG_PAUSE_THRESHOLD = 0x16, + HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, +}; + +struct mcs7830_data { + u8 multi_filter[8]; + u8 config; +}; + +static const char driver_name[] = "MOSCHIP usb-ethernet driver"; + +static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_device *xdev = dev->udev; + int ret; + + ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, + MCS7830_RD_BMREQ, 0x0000, index, data, + size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); + return ret; +} + +static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_device *xdev = dev->udev; + int ret; + + ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, + MCS7830_WR_BMREQ, 0x0000, index, data, + size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); + return ret; +} + +static void mcs7830_async_cmd_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + + if (urb->status < 0) + printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d", + urb->status); + + kfree(req); + usb_free_urb(urb); +} + +static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_ctrlrequest *req; + int ret; + struct urb *urb; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + dev_dbg(&dev->udev->dev, "Error allocating URB " + "in write_cmd_async!"); + return; + } + + req = kmalloc(sizeof *req, GFP_ATOMIC); + if (!req) { + dev_err(&dev->udev->dev, "Failed to allocate memory for " + "control request"); + goto out; + } + req->bRequestType = MCS7830_WR_BMREQ; + req->bRequest = MCS7830_WR_BREQ; + req->wValue = 0; + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, size, + mcs7830_async_cmd_callback, req); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(&dev->udev->dev, "Error submitting the control " + "message: ret=%d", ret); + goto out; + } + return; +out: + kfree(req); + usb_free_urb(urb); +} + +static int mcs7830_get_address(struct usbnet *dev) +{ + int ret; + ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, + dev->net->dev_addr); + if (ret < 0) + return ret; + return 0; +} + +static int mcs7830_read_phy(struct usbnet *dev, u8 index) +{ + int ret; + int i; + __le16 val; + + u8 cmd[2] = { + HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, + }; + + mutex_lock(&dev->phy_mutex); + /* write the MII command */ + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if (ret < 0) + goto out; + + /* wait for the data to become valid, should be within < 1ms */ + for (i = 0; i < 10; i++) { + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) + break; + ret = -EIO; + msleep(1); + } + if (ret < 0) + goto out; + + /* read actual register contents */ + ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); + if (ret < 0) + goto out; + ret = le16_to_cpu(val); + dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", + index, val, i); +out: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) +{ + int ret; + int i; + __le16 le_val; + + u8 cmd[2] = { + HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), + }; + + mutex_lock(&dev->phy_mutex); + + /* write the new register contents */ + le_val = cpu_to_le16(val); + ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); + if (ret < 0) + goto out; + + /* write the MII command */ + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if (ret < 0) + goto out; + + /* wait for the command to be accepted by the PHY */ + for (i = 0; i < 10; i++) { + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) + break; + ret = -EIO; + msleep(1); + } + if (ret < 0) + goto out; + + ret = 0; + dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", + index, val, i); +out: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +/* + * This algorithm comes from the original mcs7830 version 1.4 driver, + * not sure if it is needed. + */ +static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) +{ + int ret; + /* Enable all media types */ + ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); + + /* First reset BMCR */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); + /* Enable Auto Neg */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); + /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART ); + return ret < 0 ? : 0; +} + + +/* + * if we can read register 22, the chip revision is C or higher + */ +static int mcs7830_get_rev(struct usbnet *dev) +{ + u8 dummy[2]; + int ret; + ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); + if (ret > 0) + return 2; /* Rev C or later */ + return 1; /* earlier revision */ +} + +/* + * On rev. C we need to set the pause threshold + */ +static void mcs7830_rev_C_fixup(struct usbnet *dev) +{ + u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; + int retry; + + for (retry = 0; retry < 2; retry++) { + if (mcs7830_get_rev(dev) == 2) { + dev_info(&dev->udev->dev, "applying rev.C fixup\n"); + mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, + 1, &pause_threshold); + } + msleep(1); + } +} + +static int mcs7830_init_dev(struct usbnet *dev) +{ + int ret; + int retry; + + /* Read MAC address from EEPROM */ + ret = -EINVAL; + for (retry = 0; retry < 5 && ret; retry++) + ret = mcs7830_get_address(dev); + if (ret) { + dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); + goto out; + } + + /* Set up PHY */ + ret = mcs7830_set_autoneg(dev, 0); + if (ret) { + dev_info(&dev->udev->dev, "Cannot set autoneg\n"); + goto out; + } + + mcs7830_rev_C_fixup(dev); + ret = 0; +out: + return ret; +} + +static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, + int location) +{ + struct usbnet *dev = netdev->priv; + return mcs7830_read_phy(dev, location); +} + +static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, + int location, int val) +{ + struct usbnet *dev = netdev->priv; + mcs7830_write_phy(dev, location, val); +} + +static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +/* credits go to asix_set_multicast */ +static void mcs7830_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; + + data->config = HIF_REG_CONFIG_TXENABLE; + + /* this should not be needed, but it doesn't work otherwise */ + data->config |= HIF_REG_CONFIG_ALLMULTICAST; + + if (net->flags & IFF_PROMISC) { + data->config |= HIF_REG_CONFIG_PROMISCIOUS; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > MCS7830_MAX_MCAST) { + data->config |= HIF_REG_CONFIG_ALLMULTICAST; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later */ + struct dev_mc_list *mc_list = net->mc_list; + u32 crc_bits; + int i; + + memset(data->multi_filter, 0, sizeof data->multi_filter); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; + data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, + sizeof data->multi_filter, + data->multi_filter); + } + + mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); +} + +static int mcs7830_get_regs_len(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + switch (mcs7830_get_rev(dev)) { + case 1: + return 21; + case 2: + return 32; + } + return 0; +} + +static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) +{ + usbnet_get_drvinfo(net, drvinfo); + drvinfo->regdump_len = mcs7830_get_regs_len(net); +} + +static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) +{ + struct usbnet *dev = netdev_priv(net); + + regs->version = mcs7830_get_rev(dev); + mcs7830_get_reg(dev, 0, regs->len, data); +} + +static struct ethtool_ops mcs7830_ethtool_ops = { + .get_drvinfo = mcs7830_get_drvinfo, + .get_regs_len = mcs7830_get_regs_len, + .get_regs = mcs7830_get_regs, + + /* common usbnet calls */ + .get_link = usbnet_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, +}; + +static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) +{ + struct net_device *net = dev->net; + int ret; + + ret = mcs7830_init_dev(dev); + if (ret) + goto out; + + net->do_ioctl = mcs7830_ioctl; + net->ethtool_ops = &mcs7830_ethtool_ops; + net->set_multicast_list = mcs7830_set_multicast; + mcs7830_set_multicast(net); + + /* reserve space for the status byte on rx */ + dev->rx_urb_size = ETH_FRAME_LEN + 1; + + dev->mii.mdio_read = mcs7830_mdio_read; + dev->mii.mdio_write = mcs7830_mdio_write; + dev->mii.dev = net; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = *((u8 *) net->dev_addr + 1); + + ret = usbnet_get_endpoints(dev, udev); +out: + return ret; +} + +/* The chip always appends a status bytes that we need to strip */ +static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + u8 status; + + if (skb->len == 0) { + dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); + return 0; + } + + skb_trim(skb, skb->len - 1); + status = skb->data[skb->len]; + + if (status != 0x20) + dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); + + return skb->len > 0; +} + +static const struct driver_info moschip_info = { + .description = "MOSCHIP 7830 usb-NET adapter", + .bind = mcs7830_bind, + .rx_fixup = mcs7830_rx_fixup, + .flags = FLAG_ETHER, + .in = 1, + .out = 2, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), + .driver_info = (unsigned long) &moschip_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver mcs7830_driver = { + .name = driver_name, + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init mcs7830_init(void) +{ + return usb_register(&mcs7830_driver); +} +module_init(mcs7830_init); + +static void __exit mcs7830_exit(void) +{ + usb_deregister(&mcs7830_driver); +} +module_exit(mcs7830_exit); + +MODULE_DESCRIPTION("USB to network adapter MCS7830)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 24bd3486ee6..760b5327b81 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -554,7 +554,7 @@ static int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); int temp; - DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); netif_stop_queue (net); @@ -669,20 +669,40 @@ done: * they'll probably want to use this base set. */ -void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) +#if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE) +#define HAVE_MII + +int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); - /* REVISIT don't always return "usbnet" */ - strncpy (info->driver, driver_name, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - strncpy (info->fw_version, dev->driver_info->description, - sizeof info->fw_version); - usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); + if (!dev->mii.mdio_read) + return -EOPNOTSUPP; + + return mii_ethtool_gset(&dev->mii, cmd); } -EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); +EXPORT_SYMBOL_GPL(usbnet_get_settings); + +int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + int retval; + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; -static u32 usbnet_get_link (struct net_device *net) + retval = mii_ethtool_sset(&dev->mii, cmd); + + /* link speed/duplex might have changed */ + if (dev->driver_info->link_reset) + dev->driver_info->link_reset(dev); + + return retval; + +} +EXPORT_SYMBOL_GPL(usbnet_set_settings); + +u32 usbnet_get_link (struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -690,9 +710,40 @@ static u32 usbnet_get_link (struct net_device *net) if (dev->driver_info->check_connect) return dev->driver_info->check_connect (dev) == 0; + /* if the device has mii operations, use those */ + if (dev->mii.mdio_read) + return mii_link_ok(&dev->mii); + /* Otherwise, say we're up (to avoid breaking scripts) */ return 1; } +EXPORT_SYMBOL_GPL(usbnet_get_link); + +int usbnet_nway_reset(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; + + return mii_nway_restart(&dev->mii); +} +EXPORT_SYMBOL_GPL(usbnet_nway_reset); + +#endif /* HAVE_MII */ + +void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) +{ + struct usbnet *dev = netdev_priv(net); + + /* REVISIT don't always return "usbnet" */ + strncpy (info->driver, driver_name, sizeof info->driver); + strncpy (info->version, DRIVER_VERSION, sizeof info->version); + strncpy (info->fw_version, dev->driver_info->description, + sizeof info->fw_version); + usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); +} +EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); u32 usbnet_get_msglevel (struct net_device *net) { @@ -712,8 +763,13 @@ EXPORT_SYMBOL_GPL(usbnet_set_msglevel); /* drivers may override default ethtool_ops in their bind() routine */ static struct ethtool_ops usbnet_ethtool_ops = { - .get_drvinfo = usbnet_get_drvinfo, +#ifdef HAVE_MII + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, .get_link = usbnet_get_link, + .nway_reset = usbnet_nway_reset, +#endif + .get_drvinfo = usbnet_get_drvinfo, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, }; @@ -1094,6 +1150,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); + mutex_init (&dev->phy_mutex); SET_MODULE_OWNER (net); dev->net = net; @@ -1225,7 +1282,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static int __init usbnet_init(void) { /* compiler should optimize this out */ - BUG_ON (sizeof (((struct sk_buff *)0)->cb) + BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)); random_ether_addr(node_id); diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index c0746f0454a..07c70abbe0e 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -30,6 +30,7 @@ struct usbnet { struct usb_device *udev; struct driver_info *driver_info; wait_queue_head_t *wait; + struct mutex phy_mutex; /* i/o info: pipes etc */ unsigned in, out; @@ -168,9 +169,13 @@ extern void usbnet_defer_kevent (struct usbnet *, int); extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); extern void usbnet_unlink_rx_urbs(struct usbnet *); +extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); +extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); +extern u32 usbnet_get_link (struct net_device *net); extern u32 usbnet_get_msglevel (struct net_device *); extern void usbnet_set_msglevel (struct net_device *, u32); extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); +extern int usbnet_nway_reset(struct net_device *net); /* messaging support includes the interface name, so it must not be * used before it has one ... notably, in minidriver bind() calls. diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5076b9d9705..2a8dd4cc943 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -54,10 +54,10 @@ config USB_SERIAL_GENERIC properly. config USB_SERIAL_AIRCABLE - tristate "AIRcable USB Bluetooth Dongle Driver (EXPERIMENTAL)" + tristate "USB AIRcable Bluetooth Dongle Driver (EXPERIMENTAL)" depends on USB_SERIAL && EXPERIMENTAL help - Say Y here if you want to use AIRcable USB Bluetoot Dongle. + Say Y here if you want to use USB AIRcable Bluetooth Dongle. To compile this driver as a module, choose M here: the module will be called aircable. @@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_MOS7720 + tristate "USB Moschip 7720 Single Port Serial Driver" + depends on USB_SERIAL + ---help--- + Say Y here if you want to use a USB Serial single port adapter from + Moschip Semiconductor Tech. + + To compile this driver as a module, choose M here: the + module will be called mos7720. + config USB_SERIAL_MOS7840 tristate "USB Moschip 7840/7820 USB Serial Driver" depends on USB_SERIAL @@ -527,8 +537,7 @@ config USB_SERIAL_OPTION The USB bus on these cards is not accessible externally. Supported devices include (some of?) those made by: - Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or - Anydata. + Option, Huawei, Audiovox, 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 8dce83340e3..a5047dc599b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 2c19f19b255..7f5d546da39 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -18,12 +18,8 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ - { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); @@ -133,6 +129,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) } urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { + kfree(buffer); dev_err(&port->dev, "%s - no more urbs?\n", __FUNCTION__); result = -ENOMEM; diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 486c7411b9a..f95d42c0d16 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -64,7 +64,11 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d3dc1a15ec6..c186b4e73c7 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,16 +1,16 @@ /* * USB FTDI SIO driver * - * Copyright (C) 1999 - 2001 - * Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2001 + * Greg Kroah-Hartman (greg@kroah.com) * Bill Ryder (bryder@sgi.com) * Copyright (C) 2002 * Kuba Ober (kuba@mareimbrium.org) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is 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. * * See Documentation/usb/usb-serial.txt for more information on using this driver * @@ -32,7 +32,7 @@ * Changed full name of USB-UIRT device to avoid "/" character. * Added FTDI's alternate PID (0x6006) for FT232/245 devices. * Added PID for "ELV USB Module UO100" from Stefan Frings. - * + * * (21/Oct/2003) Ian Abbott * Renamed some VID/PID macros for Matrix Orbital and Perle Systems * devices. Removed Matrix Orbital and Perle Systems devices from the @@ -69,7 +69,7 @@ * does not incure any measurable overhead. This also relies on the fact * that we have proper reference counting logic for urbs. I nicked this * from Greg KH's Visor driver. - * + * * (23/Jun/2003) Ian Abbott * Reduced flip buffer pushes and corrected a data length test in * ftdi_read_bulk_callback. @@ -77,7 +77,7 @@ * * (21/Jun/2003) Erik Nygren * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. - * See <http://www.home-electro.com/tira1.htm>. Only operates properly + * See <http://www.home-electro.com/tira1.htm>. Only operates properly * at 100000 and RTS-CTS, so set custom divisor mode on startup. * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. * @@ -137,17 +137,17 @@ * (17/Feb/2003) Bill Ryder * Added write urb buffer pool on a per device basis * Added more checking for open file on callbacks (fixed OOPS) - * Added CrystalFontz 632 and 634 PIDs + * Added CrystalFontz 632 and 634 PIDs * (thanx to CrystalFontz for the sample devices - they flushed out * some driver bugs) * Minor debugging message changes * Added throttle, unthrottle and chars_in_buffer functions * Fixed FTDI_SIO (the original device) bug * Fixed some shutdown handling - * - * - * - * + * + * + * + * * (07/Jun/2002) Kuba Ober * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor * function. It was getting too complex. @@ -158,7 +158,7 @@ * * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch * Not tested by me but it doesn't break anything I use. - * + * * (04/Jan/2002) Kuba Ober * Implemented 38400 baudrate kludge, where it can be substituted with other * values. That's the only way to set custom baudrates. @@ -179,7 +179,7 @@ * (the previous version caused panics) * Removed port iteration code since the device only has one I/O port and it * was wrong anyway. - * + * * (31/May/2001) gkh * Switched from using spinlock to a semaphore, which fixes lots of problems. * @@ -188,16 +188,16 @@ * Cleaned up comments for 8U232 * Added parity, framing and overrun error handling * Added receive break handling. - * + * * (04/08/2001) gb * Identify version on module load. - * + * * (18/March/2001) Bill Ryder * (Not released) * Added send break handling. (requires kernel patch too) * Fixed 8U232AM hardware RTS/CTS etc status reporting. * Added flipbuf fix copied from generic device - * + * * (12/3/2000) Bill Ryder * Added support for 8U232AM device. * Moved PID and VIDs into header file only. @@ -211,14 +211,14 @@ * Cleaned up comments. Removed multiple PID/VID definitions. * Factorised cts/dtr code * Made use of __FUNCTION__ in dbg's - * + * * (11/01/2000) Adam J. Richter * usb_device_id table support - * + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. - * + * * (09/11/2000) gkh * Removed DEBUG #ifdefs with call to usb_serial_debug_data * @@ -226,11 +226,11 @@ * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. * - * (04/04/2000) Bill Ryder + * (04/04/2000) Bill Ryder * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are * handled elsewhere in the tty io driver chain). * - * (03/30/2000) Bill Ryder + * (03/30/2000) Bill Ryder * Implemented lots of ioctls * Fixed a race condition in write * Changed some dbg's to errs @@ -311,6 +311,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, @@ -444,13 +445,13 @@ static struct usb_device_id id_table_combined [] = { /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ - { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, - { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, @@ -511,6 +512,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, + { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -522,7 +524,7 @@ static struct usb_driver ftdi_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; static const char *ftdi_chip_name[] = { @@ -548,13 +550,13 @@ struct ftdi_private { int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ __u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */ - int write_offset; /* This is the offset in the usb data block to write the serial data - + int write_offset; /* This is the offset in the usb data block to write the serial data - * it is different between devices */ int flags; /* some ASYNC_xxxx flags are supported */ unsigned long last_dtr_rts; /* saved modem control outputs */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - char prev_status, diff_status; /* Used for TIOCMIWAIT */ + char prev_status, diff_status; /* Used for TIOCMIWAIT */ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ struct work_struct rx_work; @@ -721,7 +723,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned urb_value |= FTDI_SIO_SET_RTS_HIGH; rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, urb_value, priv->interface, buf, 0, WDR_TIMEOUT); @@ -768,7 +770,7 @@ static int change_speed(struct usb_serial_port *port) if (priv->interface) { /* FT2232C */ urb_index = (__u16)((urb_index << 8) | priv->interface); } - + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_BAUDRATE_REQUEST, @@ -827,7 +829,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) /* 3. Convert baudrate to device-specific divisor */ - if (!baud) baud = 9600; + if (!baud) baud = 9600; switch(priv->chip_type) { case SIO: /* SIO chip */ switch(baud) { @@ -843,7 +845,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) case 115200: div_value = ftdi_sio_b115200; break; } /* baud */ if (div_value == 0) { - dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); + dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); div_value = ftdi_sio_b9600; div_okay = 0; } @@ -925,7 +927,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _ /* Make the changes - these are privileged changes! */ priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); + (new_serial.flags & ASYNC_FLAGS)); priv->custom_divisor = new_serial.custom_divisor; port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -950,7 +952,7 @@ check_and_exit: (old_priv.custom_divisor != priv->custom_divisor))) { change_speed(port); } - + return (0); } /* set_serial_info */ @@ -1022,18 +1024,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a struct usb_device *udev; unsigned short latency = 0; int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s",__FUNCTION__); - + rv = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), FTDI_SIO_GET_LATENCY_TIMER_REQUEST, FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, (char*) &latency, 1, WDR_TIMEOUT); - + if (rv < 0) { dev_err(dev, "Unable to read latency timer: %i", rv); return -EIO; @@ -1051,23 +1053,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute * char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s: setting latency timer = %i", __FUNCTION__, v); - + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - v, priv->interface, + v, priv->interface, buf, 0, WDR_TIMEOUT); - + if (rv < 0) { dev_err(dev, "Unable to write latency timer: %i", rv); return -EIO; } - + return count; } @@ -1082,23 +1084,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s: setting event char = %i", __FUNCTION__, v); - + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, - v, priv->interface, + v, priv->interface, buf, 0, WDR_TIMEOUT); - + if (rv < 0) { dbg("Unable to write event character: %i", rv); return -EIO; } - + return count; } @@ -1135,11 +1137,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial) struct ftdi_private *priv; struct usb_device *udev; - dbg("%s",__FUNCTION__); + dbg("%s",__FUNCTION__); priv = usb_get_serial_port_data(serial->port[0]); udev = serial->dev; - + /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&udev->dev, &dev_attr_event_char); @@ -1147,7 +1149,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial) device_remove_file(&udev->dev, &dev_attr_latency_timer); } } - + } /* @@ -1258,7 +1260,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) } /* ftdi_HE_TIRA1_setup */ -/* ftdi_shutdown is called from usbserial:usb_serial_disconnect +/* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * * usbserial:usb_serial_disconnect @@ -1269,16 +1271,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) static void ftdi_shutdown (struct usb_serial *serial) { /* ftdi_shutdown */ - + struct usb_serial_port *port = serial->port[0]; struct ftdi_private *priv = usb_get_serial_port_data(port); dbg("%s", __FUNCTION__); remove_sysfs_attrs(serial); - - /* all open ports are closed at this point - * (by usbserial.c:__serial_close, which calls ftdi_close) + + /* all open ports are closed at this point + * (by usbserial.c:__serial_close, which calls ftdi_close) */ if (priv) { @@ -1293,7 +1295,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned long flags; - + int result = 0; char buf[1]; /* Needed for the usb_control_msg I think */ @@ -1312,8 +1314,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, - FTDI_SIO_RESET_SIO, + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change @@ -1350,12 +1352,12 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) -/* +/* * usbserial:__serial_close only calls ftdi_close if the point is open * * This only gets called when it is the last close - * - * + * + * */ static void ftdi_close (struct usb_serial_port *port, struct file *filp) @@ -1368,14 +1370,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) if (c_cflag & HUPCL){ /* Disable flow control */ - if (usb_control_msg(port->serial->dev, + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); - } + } /* drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); @@ -1384,14 +1386,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) /* cancel any scheduled reading */ cancel_delayed_work(&priv->rx_work); flush_scheduled_work(); - + /* shutdown our bulk read */ if (port->read_urb) usb_kill_urb(port->read_urb); } /* ftdi_close */ - + /* The SIO requires the first byte to have: * B0 1 * B1 0 @@ -1423,7 +1425,7 @@ static int ftdi_write (struct usb_serial_port *port, return 0; } spin_unlock_irqrestore(&priv->tx_lock, flags); - + data_offset = priv->write_offset; dbg("data_offset set to %d",data_offset); @@ -1462,7 +1464,7 @@ static int ftdi_write (struct usb_serial_port *port, user_pktsz = todo; } /* Write the control byte at the front of the packet*/ - *first_byte = 1 | ((user_pktsz) << 2); + *first_byte = 1 | ((user_pktsz) << 2); /* Copy data for packet */ memcpy (first_byte + data_offset, current_position, user_pktsz); @@ -1479,7 +1481,7 @@ static int ftdi_write (struct usb_serial_port *port, usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); /* fill the buffer and send it */ - usb_fill_bulk_urb(urb, port->serial->dev, + usb_fill_bulk_urb(urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), buffer, transfer_size, ftdi_write_bulk_callback, port); @@ -1520,7 +1522,7 @@ static void ftdi_write_bulk_callback (struct urb *urb) kfree (urb->transfer_buffer); dbg("%s - port %d", __FUNCTION__, port->number); - + if (urb->status) { dbg("nonzero write bulk status received: %d", urb->status); return; @@ -1651,7 +1653,7 @@ static void ftdi_process_read (void *param) struct tty_struct *tty; struct ftdi_private *priv; char error_flag; - unsigned char *data; + unsigned char *data; int i; int result; @@ -1759,7 +1761,7 @@ static void ftdi_process_read (void *param) } if (length > 0) { for (i = 2; i < length+2; i++) { - /* Note that the error flag is duplicated for + /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ tty_insert_flip_char(tty, data[packet_offset+i], error_flag); @@ -1773,7 +1775,7 @@ static void ftdi_process_read (void *param) This doesn't work well since the application receives a never ending stream of bad data - even though new data hasn't been sent. Therefore I (bill) have taken this out. - However - this might make sense for framing errors and so on + However - this might make sense for framing errors and so on so I am leaving the code in for now. */ else { @@ -1827,7 +1829,7 @@ static void ftdi_process_read (void *param) /* if the port is closed stop trying to read */ if (port->open_count > 0){ /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, + 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, ftdi_read_bulk_callback, port); @@ -1844,9 +1846,9 @@ static void ftdi_process_read (void *param) static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) { struct ftdi_private *priv = usb_get_serial_port_data(port); - __u16 urb_value = 0; + __u16 urb_value = 0; char buf[1]; - + /* break_state = -1 to turn on break, and 0 to turn off break */ /* see drivers/char/tty_io.c to see it used */ /* last_set_data_urb_value NEVER has the break bit set in it */ @@ -1854,20 +1856,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) if (break_state) { urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; } else { - urb_value = priv->last_set_data_urb_value; + urb_value = priv->last_set_data_urb_value; } - + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); - } + } dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value); - + } @@ -1883,12 +1885,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ struct ftdi_private *priv = usb_get_serial_port_data(port); __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ - + // Added for xon/xoff support unsigned int iflag = port->tty->termios->c_iflag; unsigned char vstop; unsigned char vstart; - + dbg("%s", __FUNCTION__); /* Force baud rate if this device requires it, unless it is set to B0. */ @@ -1906,20 +1908,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ cflag = port->tty->termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to + /* FIXME -For this cut I don't care if the line is really changing or + not - so just do the change regardless - should be able to compare old_termios and tty->termios */ - /* NOTE These routines can get interrupted by - ftdi_sio_read_bulk_callback - need to examine what this + /* NOTE These routines can get interrupted by + ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ - + /* Set number of data bits, parity, stop bits */ - + urb_value = 0; urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : FTDI_SIO_SET_DATA_STOP_BITS_1); - urb_value |= (cflag & PARENB ? - (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : + urb_value |= (cflag & PARENB ? + (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : FTDI_SIO_SET_DATA_PARITY_EVEN) : FTDI_SIO_SET_DATA_PARITY_NONE); if (cflag & CSIZE) { @@ -1936,25 +1938,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* This is needed by the break command since it uses the same command - but is * or'ed with this value */ priv->last_set_data_urb_value = urb_value; - + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, buf, 0, WDR_SHORT_TIMEOUT) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); - } + } /* Now do the baudrate */ if ((cflag & CBAUD) == B0 ) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); - } + } /* Drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { @@ -1972,16 +1974,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ if (cflag & CRTSCTS) { dbg("%s Setting to CRTSCTS flow control", __FUNCTION__); - if (usb_control_msg(dev, + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); - } - - } else { + } + + } else { /* * Xon/Xoff code * @@ -2011,16 +2013,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */ /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ dbg("%s Turning off hardware flow control", __FUNCTION__); - if (usb_control_msg(dev, + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); - } + } } - + } return; } /* ftdi_termios */ @@ -2036,11 +2038,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) switch (priv->chip_type) { case SIO: /* Request the status from the device */ - if ((ret = usb_control_msg(port->serial->dev, + if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, 0, buf, 1, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2052,11 +2054,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ - if ((ret = usb_control_msg(port->serial->dev, + if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2067,12 +2069,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) return -EFAULT; break; } - + return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; + priv->last_dtr_rts; } static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) @@ -2138,11 +2140,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne break; default: break; - + } - /* This is not necessarily an error - turns out the higher layers will do + /* This is not necessarily an error - turns out the higher layers will do * some ioctls itself (see comment above) */ dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd); @@ -2199,7 +2201,7 @@ static int __init ftdi_init (void) if (retval) goto failed_sio_register; retval = usb_register(&ftdi_driver); - if (retval) + if (retval) goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index f0edb87d2dd..bae117d359a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -55,6 +55,9 @@ /* iPlus device */ #define FTDI_IPLUS_PID 0xD070 /* Product Id */ +/* DMX4ALL DMX Interfaces */ +#define FTDI_DMX4ALL 0xC850 + /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */ /* they use the ftdi chipset for the USB interface and the vendor id is the same */ #define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ @@ -175,9 +178,15 @@ #define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ /* + * FTDI USB UART chips used in construction projects from the + * Elektor Electronics magazine (http://elektor-electronics.co.uk) + */ +#define ELEKTOR_VID 0x0C7D +#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ + +/* * DSS-20 Sync Station for Sony Ericsson P800 */ - #define FTDI_DSS20_PID 0xFC82 /* diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6238aff1e77..d72cf8bc7f7 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -320,6 +320,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ { USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */ + { USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC USB Modem */ { USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A03) }, /* PocketPC USB Sync */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c new file mode 100644 index 00000000000..82cd15b894b --- /dev/null +++ b/drivers/usb/serial/mos7720.c @@ -0,0 +1,1683 @@ +/* + * mos7720.c + * Controls the Moschip 7720 usb to dual port serial convertor + * + * Copyright 2006 Moschip Semiconductor Tech. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * Developed by: + * VijayaKumar.G.N. <vijaykumar@aspirecom.net> + * AjayKumar <ajay@aspirecom.net> + * Gurudeva.N. <gurudev@aspirecom.net> + * + * Cleaned up from the original by: + * Greg Kroah-Hartman <gregkh@suse.de> + * + * Originally based on drivers/usb/serial/io_edgeport.c which is: + * Copyright (C) 2000 Inside Out Networks, All rights reserved. + * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <asm/uaccess.h> + + +/* + * Version Information + */ +#define DRIVER_VERSION "1.0.0.4F" +#define DRIVER_AUTHOR "Aspire Communications pvt Ltd." +#define DRIVER_DESC "Moschip USB Serial Driver" + +/* default urb timeout */ +#define MOS_WDR_TIMEOUT (HZ * 5) + +#define MOS_PORT1 0x0200 +#define MOS_PORT2 0x0300 +#define MOS_VENREG 0x0000 +#define MOS_MAX_PORT 0x02 +#define MOS_WRITE 0x0E +#define MOS_READ 0x0D + +/* Interrupt Rotinue Defines */ +#define SERIAL_IIR_RLS 0x06 +#define SERIAL_IIR_RDA 0x04 +#define SERIAL_IIR_CTI 0x0c +#define SERIAL_IIR_THR 0x02 +#define SERIAL_IIR_MS 0x00 + +#define NUM_URBS 16 /* URB Count */ +#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ + +/* This structure holds all of the local port information */ +struct moschip_port +{ + __u8 shadowLCR; /* last LCR value received */ + __u8 shadowMCR; /* last MCR value received */ + __u8 shadowMSR; /* last MSR value received */ + char open; + struct async_icount icount; + struct usb_serial_port *port; /* loop back to the owner */ + struct urb *write_urb_pool[NUM_URBS]; +}; + +/* This structure holds all of the individual serial device information */ +struct moschip_serial +{ + int interrupt_started; +}; + +static int debug; + +#define USB_VENDOR_ID_MOSCHIP 0x9710 +#define MOSCHIP_DEVICE_ID_7720 0x7720 +#define MOSCHIP_DEVICE_ID_7715 0x7715 + +static struct usb_device_id moschip_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) }, + { } /* terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, moschip_port_id_table); + + +/* + * mos7720_interrupt_callback + * this is the callback function for when we have received data on the + * interrupt endpoint. + */ +static void mos7720_interrupt_callback(struct urb *urb) +{ + int result; + int length; + __u32 *data; + unsigned int status; + __u8 sp1; + __u8 sp2; + __u8 st; + + dbg("%s"," : Entering\n"); + + if (!urb) { + dbg("%s","Invalid Pointer !!!!:\n"); + return; + } + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, + urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, + urb->status); + goto exit; + } + + length = urb->actual_length; + data = urb->transfer_buffer; + + /* Moschip get 4 bytes + * Byte 1 IIR Port 1 (port.number is 0) + * Byte 2 IIR Port 2 (port.number is 1) + * Byte 3 -------------- + * Byte 4 FIFO status for both */ + if (length && length > 4) { + dbg("Wrong data !!!"); + return; + } + + status = *data; + + sp1 = (status & 0xff000000)>>24; + sp2 = (status & 0x00ff0000)>>16; + st = status & 0x000000ff; + + if ((sp1 & 0x01) || (sp2 & 0x01)) { + /* No Interrupt Pending in both the ports */ + dbg("No Interrupt !!!"); + } else { + switch (sp1 & 0x0f) { + case SERIAL_IIR_RLS: + dbg("Serial Port 1: Receiver status error or address " + "bit detected in 9-bit mode\n"); + break; + case SERIAL_IIR_CTI: + dbg("Serial Port 1: Receiver time out"); + break; + case SERIAL_IIR_MS: + dbg("Serial Port 1: Modem status change"); + break; + } + + switch (sp2 & 0x0f) { + case SERIAL_IIR_RLS: + dbg("Serial Port 2: Receiver status error or address " + "bit detected in 9-bit mode"); + break; + case SERIAL_IIR_CTI: + dbg("Serial Port 2: Receiver time out"); + break; + case SERIAL_IIR_MS: + dbg("Serial Port 2: Modem status change"); + break; + } + } + +exit: + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) + dev_err(&urb->dev->dev, + "%s - Error %d submitting control urb\n", + __FUNCTION__, result); + return; +} + +/* + * mos7720_bulk_in_callback + * this is the callback function for when we have received data on the + * bulk in endpoint. + */ +static void mos7720_bulk_in_callback(struct urb *urb) +{ + int status; + unsigned char *data ; + struct usb_serial_port *port; + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + if (urb->status) { + dbg("nonzero read bulk status received: %d",urb->status); + return; + } + + mos7720_port = urb->context; + if (!mos7720_port) { + dbg("%s","NULL mos7720_port pointer \n"); + return ; + } + + port = mos7720_port->port; + + dbg("Entering...%s", __FUNCTION__); + + data = urb->transfer_buffer; + + tty = port->tty; + if (tty && urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } + + if (!port->read_urb) { + dbg("URB KILLED !!!"); + return; + } + + if (port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = port->serial->dev; + + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } +} + +/* + * mos7720_bulk_out_data_callback + * this is the callback function for when we have finished sending serial + * data on the bulk out endpoint. + */ +static void mos7720_bulk_out_data_callback(struct urb *urb) +{ + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + if (urb->status) { + dbg("nonzero write bulk status received:%d", urb->status); + return; + } + + mos7720_port = urb->context; + if (!mos7720_port) { + dbg("NULL mos7720_port pointer"); + return ; + } + + dbg("Entering ........."); + + tty = mos7720_port->port->tty; + + if (tty && mos7720_port->open) { + /* let the tty driver wakeup if it has a special * + * write_wakeup function */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&tty->write_wait); + } + + /* schedule_work(&mos7720_port->port->work); */ +} + +/* + * send_mos_cmd + * this function will be used for sending command to device + */ +static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, + __u16 index, void *data) +{ + int status; + unsigned int pipe; + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + __u8 requesttype; + __u16 size = 0x0000; + + if (value < MOS_MAX_PORT) { + if (product == MOSCHIP_DEVICE_ID_7715) { + value = value*0x100+0x100; + } else { + value = value*0x100+0x200; + } + } else { + value = 0x0000; + if ((product == MOSCHIP_DEVICE_ID_7715) && + (index != 0x08)) { + dbg("serial->product== MOSCHIP_DEVICE_ID_7715"); + //index = 0x01 ; + } + } + + if (request == MOS_WRITE) { + request = (__u8)MOS_WRITE; + requesttype = (__u8)0x40; + value = value + (__u16)*((unsigned char *)data); + data = NULL; + pipe = usb_sndctrlpipe(serial->dev, 0); + } else { + request = (__u8)MOS_READ; + requesttype = (__u8)0xC0; + size = 0x01; + pipe = usb_rcvctrlpipe(serial->dev,0); + } + + status = usb_control_msg(serial->dev, pipe, request, requesttype, + value, index, data, size, MOS_WDR_TIMEOUT); + + if (status < 0) + dbg("Command Write failed Value %x index %x\n",value,index); + + return status; +} + +static int mos7720_open(struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial; + struct usb_serial_port *port0; + struct urb *urb; + struct moschip_serial *mos7720_serial; + struct moschip_port *mos7720_port; + int response; + int port_number; + char data; + int j; + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return -ENODEV; + + port0 = serial->port[0]; + + mos7720_serial = usb_get_serial_data(serial); + + if (mos7720_serial == NULL || port0 == NULL) + return -ENODEV; + + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + + /* Initialising the write urb pool */ + for (j = 0; j < NUM_URBS; ++j) { + urb = usb_alloc_urb(0,SLAB_ATOMIC); + mos7720_port->write_urb_pool[j] = urb; + + if (urb == NULL) { + err("No more urbs???"); + continue; + } + + urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (!urb->transfer_buffer) { + err("%s-out of memory for urb buffers.", __FUNCTION__); + continue; + } + } + + /* Initialize MCS7720 -- Write Init values to corresponding Registers + * + * Register Index + * 1 : IER + * 2 : FCR + * 3 : LCR + * 4 : MCR + * + * 0x08 : SP1/2 Control Reg + */ + port_number = port->number - port->serial->minor; + send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); + dbg("SS::%p LSR:%x\n",mos7720_port, data); + + dbg("Check:Sending Command .........."); + + data = 0x02; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data); + data = 0x02; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + + data = 0xCF; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + data = 0x03; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x0b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + +/* data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data); + data = 0x03; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); + data = 0x00; + send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); +*/ + data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + + data = data | (port->number - port->serial->minor + 1); + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + data = 0x83; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x03; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + +//Matrix + + /* force low_latency on so that our tty_push actually forces * + * the data through,otherwise it is scheduled, and with * + * high data rates (like with OHCI) data can get lost. */ + + if (port->tty) + port->tty->low_latency = 1; + + /* see if we've set up our endpoint info yet * + * (can't set it up in mos7720_startup as the * + * structures were not set up at that time.) */ + if (!mos7720_serial->interrupt_started) { + dbg("Interrupt buffer NULL !!!"); + + /* not set up yet, so do it now */ + mos7720_serial->interrupt_started = 1; + + dbg("To Submit URB !!!"); + + /* set up our interrupt urb */ + usb_fill_int_urb(port0->interrupt_in_urb, serial->dev, + usb_rcvintpipe(serial->dev, + port->interrupt_in_endpointAddress), + port0->interrupt_in_buffer, + port0->interrupt_in_urb->transfer_buffer_length, + mos7720_interrupt_callback, mos7720_port, + port0->interrupt_in_urb->interval); + + /* start interrupt read for this mos7720 this interrupt * + * will continue as long as the mos7720 is connected */ + dbg("Submit URB over !!!"); + response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL); + if (response) + dev_err(&port->dev, + "%s - Error %d submitting control urb", + __FUNCTION__, response); + } + + /* set up our bulk in urb */ + usb_fill_bulk_urb(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, + port->read_urb->transfer_buffer_length, + mos7720_bulk_in_callback, mos7720_port); + response = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (response) + dev_err(&port->dev, + "%s - Error %d submitting read urb", __FUNCTION__, response); + + /* initialize our icount structure */ + memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); + + /* initialize our port settings */ + mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ + + /* send a open port command */ + mos7720_port->open = 1; + + return 0; +} + +/* + * mos7720_chars_in_buffer + * this function is called by the tty driver when it wants to know how many + * bytes of data we currently have outstanding in the port (data that has + * been written, but hasn't made it out the port yet) + * If successful, we return the number of bytes left to be written in the + * system, + * Otherwise we return a negative error number. + */ +static int mos7720_chars_in_buffer(struct usb_serial_port *port) +{ + int i; + int chars = 0; + struct moschip_port *mos7720_port; + + dbg("%s:entering ...........", __FUNCTION__); + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("%s:leaving ...........", __FUNCTION__); + return -ENODEV; + } + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) + chars += URB_TRANSFER_BUFFER_SIZE; + } + dbg("%s - returns %d", __FUNCTION__, chars); + return chars; +} + +static void mos7720_close(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial; + struct moschip_port *mos7720_port; + char data; + int j; + + dbg("mos7720_close:entering..."); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return; + + for (j = 0; j < NUM_URBS; ++j) + usb_kill_urb(mos7720_port->write_urb_pool[j]); + + /* Freeing Write URBs */ + for (j = 0; j < NUM_URBS; ++j) { + if (mos7720_port->write_urb_pool[j]) { + kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); + usb_free_urb(mos7720_port->write_urb_pool[j]); + } + } + + /* While closing port, shutdown all bulk read, write * + * and interrupt read if they exists */ + if (serial->dev) { + dbg("Shutdown bulk write"); + usb_kill_urb(port->write_urb); + dbg("Shutdown bulk read"); + usb_kill_urb(port->read_urb); + } + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x01, &data); + + mos7720_port->open = 0; + + dbg("Leaving %s", __FUNCTION__); +} + +static void mos7720_break(struct usb_serial_port *port, int break_state) +{ + unsigned char data; + struct usb_serial *serial; + struct moschip_port *mos7720_port; + + dbg("Entering %s", __FUNCTION__); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return; + + if (break_state == -1) + data = mos7720_port->shadowLCR | UART_LCR_SBC; + else + data = mos7720_port->shadowLCR & ~UART_LCR_SBC; + + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x03, &data); + + return; +} + +/* + * mos7720_write_room + * this function is called by the tty driver when it wants to know how many + * bytes of data we can accept for a specific port. + * If successful, we return the amount of room that we have for this port + * Otherwise we return a negative error number. + */ +static int mos7720_write_room(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + int room = 0; + int i; + + dbg("%s:entering ...........", __FUNCTION__); + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("%s:leaving ...........", __FUNCTION__); + return -ENODEV; + } + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) + room += URB_TRANSFER_BUFFER_SIZE; + } + + dbg("%s - returns %d", __FUNCTION__, room); + return room; +} + +static int mos7720_write(struct usb_serial_port *port, + const unsigned char *data, int count) +{ + int status; + int i; + int bytes_sent = 0; + int transfer_size; + + struct moschip_port *mos7720_port; + struct usb_serial *serial; + struct urb *urb; + const unsigned char *current_position = data; + + dbg("%s:entering ...........", __FUNCTION__); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("mos7720_port is NULL"); + return -ENODEV; + } + + /* try to find a free urb in the list */ + urb = NULL; + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { + urb = mos7720_port->write_urb_pool[i]; + dbg("URB:%d",i); + break; + } + } + + if (urb == NULL) { + dbg("%s - no more free urbs", __FUNCTION__); + goto exit; + } + + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err("%s no more kernel memory...", __FUNCTION__); + goto exit; + } + } + transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE); + + memcpy(urb->transfer_buffer, current_position, transfer_size); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, + urb->transfer_buffer); + + /* fill urb with data and submit */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, transfer_size, + mos7720_bulk_out_data_callback, mos7720_port); + + /* send it down the pipe */ + status = usb_submit_urb(urb,GFP_ATOMIC); + if (status) { + err("%s - usb_submit_urb(write bulk) failed with status = %d", + __FUNCTION__, status); + bytes_sent = status; + goto exit; + } + bytes_sent = transfer_size; + +exit: + return bytes_sent; +} + +static void mos7720_throttle(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + struct tty_struct *tty; + int status; + + dbg("%s- port %d\n", __FUNCTION__, port->number); + + mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + if (!mos7720_port->open) { + dbg("port not opened"); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + tty = port->tty; + if (!tty) { + dbg("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the stop character */ + if (I_IXOFF(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + status = mos7720_write(port, &stop_char, 1); + if (status <= 0) + return; + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + mos7720_port->shadowMCR &= ~UART_MCR_RTS; + status = send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, + UART_MCR, &mos7720_port->shadowMCR); + if (status != 0) + return; + } +} + +static void mos7720_unthrottle(struct usb_serial_port *port) +{ + struct tty_struct *tty; + int status; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + tty = port->tty; + if (!tty) { + dbg("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the start character */ + if (I_IXOFF(tty)) { + unsigned char start_char = START_CHAR(tty); + status = mos7720_write(port, &start_char, 1); + if (status <= 0) + return; + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + mos7720_port->shadowMCR |= UART_MCR_RTS; + status = send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, + UART_MCR, &mos7720_port->shadowMCR); + if (status != 0) + return; + } +} + +static int set_higher_rates(struct moschip_port *mos7720_port, + unsigned int baud) +{ + unsigned char data; + struct usb_serial_port *port; + struct usb_serial *serial; + int port_number; + + if (mos7720_port == NULL) + return -EINVAL; + + port = mos7720_port->port; + serial = port->serial; + + /*********************************************** + * Init Sequence for higher rates + ***********************************************/ + dbg("Sending Setting Commands .........."); + port_number = port->number - port->serial->minor; + + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + data = 0x0CF; + send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); + data = 0x00b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x00b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + data = 0x000; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + + /*********************************************** + * Set for higher rates * + ***********************************************/ + + data = baud * 0x10; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data); + + data = 0x003; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x003; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + data = 0x02b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x02b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + /*********************************************** + * Set DLL/DLM + ***********************************************/ + + data = mos7720_port->shadowLCR | UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + + data = 0x001; /* DLL */ + send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); + data = 0x000; /* DLM */ + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + + data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + + return 0; +} + +/* baud rate information */ +struct divisor_table_entry +{ + __u32 baudrate; + __u16 divisor; +}; + +/* Define table of divisors for moschip 7720 hardware * + * These assume a 3.6864MHz crystal, the standard /16, and * + * MCR.7 = 0. */ +static struct divisor_table_entry divisor_table[] = { + { 50, 2304}, + { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ + { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ + { 150, 768}, + { 300, 384}, + { 600, 192}, + { 1200, 96}, + { 1800, 64}, + { 2400, 48}, + { 4800, 24}, + { 7200, 16}, + { 9600, 12}, + { 19200, 6}, + { 38400, 3}, + { 57600, 2}, + { 115200, 1}, +}; + +/***************************************************************************** + * calc_baud_rate_divisor + * this function calculates the proper baud rate divisor for the specified + * baud rate. + *****************************************************************************/ +static int calc_baud_rate_divisor(int baudrate, int *divisor) +{ + int i; + __u16 custom; + __u16 round1; + __u16 round; + + + dbg("%s - %d", __FUNCTION__, baudrate); + + for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { + if (divisor_table[i].baudrate == baudrate) { + *divisor = divisor_table[i].divisor; + return 0; + } + } + + /* After trying for all the standard baud rates * + * Try calculating the divisor for this baud rate */ + if (baudrate > 75 && baudrate < 230400) { + /* get the divisor */ + custom = (__u16)(230400L / baudrate); + + /* Check for round off */ + round1 = (__u16)(2304000L / baudrate); + round = (__u16)(round1 - (custom * 10)); + if (round > 4) + custom++; + *divisor = custom; + + dbg("Baud %d = %d",baudrate, custom); + return 0; + } + + dbg("Baud calculation Failed..."); + return -EINVAL; +} + +/* + * send_cmd_write_baud_rate + * this function sends the proper command to change the baud rate of the + * specified port. + */ +static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, + int baudrate) +{ + struct usb_serial_port *port; + struct usb_serial *serial; + int divisor; + int status; + unsigned char data; + unsigned char number; + + if (mos7720_port == NULL) + return -1; + + port = mos7720_port->port; + serial = port->serial; + + dbg("%s: Entering ..........", __FUNCTION__); + + number = port->number - port->serial->minor; + dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate); + + /* Calculate the Divisor */ + status = calc_baud_rate_divisor(baudrate, &divisor); + if (status) { + err("%s - bad baud rate", __FUNCTION__); + return status; + } + + /* Enable access to divisor latch */ + data = mos7720_port->shadowLCR | UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); + + /* Write the divisor */ + data = ((unsigned char)(divisor & 0xff)); + send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); + + data = ((unsigned char)((divisor & 0xff00) >> 8)); + send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); + + /* Disable access to divisor latch */ + data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); + + return status; +} + +/* + * change_port_settings + * This routine is called to set the UART on the device to match + * the specified new settings. + */ +static void change_port_settings(struct moschip_port *mos7720_port, + struct termios *old_termios) +{ + struct usb_serial_port *port; + struct usb_serial *serial; + struct tty_struct *tty; + int baud; + unsigned cflag; + unsigned iflag; + __u8 mask = 0xff; + __u8 lData; + __u8 lParity; + __u8 lStop; + int status; + int port_number; + char data; + + if (mos7720_port == NULL) + return ; + + port = mos7720_port->port; + serial = port->serial; + port_number = port->number - port->serial->minor; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + tty = mos7720_port->port->tty; + + if ((!tty) || (!tty->termios)) { + dbg("%s - no tty structures", __FUNCTION__); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + lData = UART_LCR_WLEN8; + lStop = 0x00; /* 1 stop bit */ + lParity = 0x00; /* No parity */ + + cflag = tty->termios->c_cflag; + iflag = tty->termios->c_iflag; + + /* Change the number of bits */ + switch (cflag & CSIZE) { + case CS5: + lData = UART_LCR_WLEN5; + mask = 0x1f; + break; + + case CS6: + lData = UART_LCR_WLEN6; + mask = 0x3f; + break; + + case CS7: + lData = UART_LCR_WLEN7; + mask = 0x7f; + break; + default: + case CS8: + lData = UART_LCR_WLEN8; + break; + } + + /* Change the Parity bit */ + if (cflag & PARENB) { + if (cflag & PARODD) { + lParity = UART_LCR_PARITY; + dbg("%s - parity = odd", __FUNCTION__); + } else { + lParity = (UART_LCR_EPAR | UART_LCR_PARITY); + dbg("%s - parity = even", __FUNCTION__); + } + + } else { + dbg("%s - parity = none", __FUNCTION__); + } + + if (cflag & CMSPAR) + lParity = lParity | 0x20; + + /* Change the Stop bit */ + if (cflag & CSTOPB) { + lStop = UART_LCR_STOP; + dbg("%s - stop bits = 2", __FUNCTION__); + } else { + lStop = 0x00; + dbg("%s - stop bits = 1", __FUNCTION__); + } + +#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ +#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ +#define LCR_PAR_MASK 0x38 /* Mask for parity field */ + + /* Update the LCR with the correct value */ + mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); + mos7720_port->shadowLCR |= (lData | lParity | lStop); + + + /* Disable Interrupts */ + data = 0x00; + send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + + data = 0xcf; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + + /* Send the updated LCR value to the mos7720 */ + data = mos7720_port->shadowLCR; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data); + + data = 0x00b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x00b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + /* set up the MCR register and send it to the mos7720 */ + mos7720_port->shadowMCR = UART_MCR_OUT2; + if (cflag & CBAUD) + mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); + + if (cflag & CRTSCTS) { + mos7720_port->shadowMCR |= (UART_MCR_XONANY); + + /* To set hardware flow control to the specified * + * serial port, in SP1/2_CONTROL_REG */ + if (port->number) { + data = 0x001; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, + 0x08, &data); + } else { + data = 0x002; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, + 0x08, &data); + } + } else { + mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); + } + + data = mos7720_port->shadowMCR; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data); + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + if (!baud) { + /* pick a default, any default... */ + dbg("Picked default baud..."); + baud = 9600; + } + + if (baud >= 230400) { + set_higher_rates(mos7720_port, baud); + /* Enable Interrupts */ + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + return; + } + + dbg("%s - baud rate = %d", __FUNCTION__, baud); + status = send_cmd_write_baud_rate(mos7720_port, baud); + + /* Enable Interrupts */ + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + + if (port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = serial->dev; + + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } + return; +} + +/* + * mos7720_set_termios + * this function is called by the tty driver when it wants to change the + * termios structure. + */ +static void mos7720_set_termios(struct usb_serial_port *port, + struct termios *old_termios) +{ + int status; + unsigned int cflag; + struct usb_serial *serial; + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + tty = port->tty; + + if (!port->tty || !port->tty->termios) { + dbg("%s - no tty or termios", __FUNCTION__); + return; + } + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + dbg("%s\n","setting termios - ASPIRE"); + + cflag = tty->termios->c_cflag; + + if (!cflag) { + printk("%s %s\n",__FUNCTION__,"cflag is NULL"); + return; + } + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("Nothing to change"); + return; + } + } + + dbg("%s - clfag %08x iflag %08x", __FUNCTION__, + tty->termios->c_cflag, + RELEVANT_IFLAG(tty->termios->c_iflag)); + + if (old_termios) + dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, + RELEVANT_IFLAG(old_termios->c_iflag)); + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* change the port settings to the new ones specified */ + change_port_settings(mos7720_port, old_termios); + + if(!port->read_urb) { + dbg("%s","URB KILLED !!!!!\n"); + return; + } + + if(port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = serial->dev; + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } + return; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + int count; + unsigned int result = 0; + + count = mos7720_chars_in_buffer(mos7720_port->port); + if (count == 0) { + dbg("%s -- Empty", __FUNCTION__); + result = TIOCSER_TEMT; + } + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +/* + * get_number_bytes_avail - get number of bytes available + * + * Purpose: Let user call ioctl to get the count of number of bytes available. + */ +static int get_number_bytes_avail(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + struct tty_struct *tty = mos7720_port->port->tty; + + if (!tty) + return -ENOIOCTLCMD; + + result = tty->read_cnt; + + dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + + return -ENOIOCTLCMD; +} + +static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, + unsigned int __user *value) +{ + unsigned int mcr ; + unsigned int arg; + unsigned char data; + + struct usb_serial_port *port; + + if (mos7720_port == NULL) + return -1; + + port = (struct usb_serial_port*)mos7720_port->port; + mcr = mos7720_port->shadowMCR; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + mcr |= UART_MCR_RTS; + if (arg & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + mcr &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + mcr &= ~UART_MCR_RTS; + if (arg & TIOCM_LOOP) + mcr &= ~UART_MCR_LOOP; + break; + + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); + mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); + break; + } + + mos7720_port->shadowMCR = mcr; + + data = mos7720_port->shadowMCR; + send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, UART_MCR, &data); + + return 0; +} + +static int get_modem_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + unsigned int msr = mos7720_port->shadowMSR; + unsigned int mcr = mos7720_port->shadowMCR; + + result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ + | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ + | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + + + dbg("%s -- %x", __FUNCTION__, result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int get_serial_info(struct moschip_port *mos7720_port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + tmp.type = PORT_16550A; + tmp.line = mos7720_port->port->serial->minor; + tmp.port = mos7720_port->port->number; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int mos7720_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct moschip_port *mos7720_port; + struct async_icount cnow; + struct async_icount cprev; + struct serial_icounter_struct icount; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return -ENODEV; + + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); + + switch (cmd) { + case TIOCINQ: + /* return number of bytes available */ + dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); + return get_number_bytes_avail(mos7720_port, + (unsigned int __user *)arg); + break; + + case TIOCSERGETLSR: + dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); + return get_lsr_info(mos7720_port, (unsigned int __user *)arg); + return 0; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, + port->number); + return set_modem_info(mos7720_port, cmd, + (unsigned int __user *)arg); + + case TIOCMGET: + dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); + return get_modem_info(mos7720_port, + (unsigned int __user *)arg); + + case TIOCGSERIAL: + dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); + return get_serial_info(mos7720_port, + (struct serial_struct __user *)arg); + + case TIOCSSERIAL: + dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); + break; + + case TIOCMIWAIT: + dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); + cprev = mos7720_port->icount; + while (1) { + if (signal_pending(current)) + return -ERESTARTSYS; + cnow = mos7720_port->icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + break; + + case TIOCGICOUNT: + cnow = mos7720_port->icount; + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, + port->number, icount.rx, icount.tx ); + if (copy_to_user((void __user *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + } + + return -ENOIOCTLCMD; +} + +static int mos7720_startup(struct usb_serial *serial) +{ + struct moschip_serial *mos7720_serial; + struct moschip_port *mos7720_port; + struct usb_device *dev; + int i; + char data; + + dbg("%s: Entering ..........", __FUNCTION__); + + if (!serial) { + dbg("Invalid Handler"); + return -ENODEV; + } + + dev = serial->dev; + + /* create our private serial structure */ + mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL); + if (mos7720_serial == NULL) { + err("%s - Out of memory", __FUNCTION__); + return -ENOMEM; + } + + usb_set_serial_data(serial, mos7720_serial); + + /* we set up the pointers to the endpoints in the mos7720_open * + * function, as the structures aren't created yet. */ + + /* set up port private structures */ + for (i = 0; i < serial->num_ports; ++i) { + mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); + if (mos7720_port == NULL) { + err("%s - Out of memory", __FUNCTION__); + usb_set_serial_data(serial, NULL); + kfree(mos7720_serial); + return -ENOMEM; + } + + /* Initialize all port interrupt end point to port 0 int + * endpoint. Our device has only one interrupt endpoint + * comman to all ports */ + serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; + + mos7720_port->port = serial->port[i]; + usb_set_serial_port_data(serial->port[i], mos7720_port); + + dbg("port number is %d", serial->port[i]->number); + dbg("serial number is %d", serial->minor); + } + + + /* setting configuration feature to one */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ); + + send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1 + dbg("LSR:%x",data); + + send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2 + dbg("LSR:%x",data); + + return 0; +} + +static void mos7720_shutdown(struct usb_serial *serial) +{ + int i; + + /* free private structure allocated for serial port */ + for (i=0; i < serial->num_ports; ++i) { + kfree(usb_get_serial_port_data(serial->port[i])); + usb_set_serial_port_data(serial->port[i], NULL); + } + + /* free private structure allocated for serial device */ + kfree(usb_get_serial_data(serial)); + usb_set_serial_data(serial, NULL); +} + +static struct usb_serial_driver moschip7720_2port_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "moschip7720", + }, + .description = "Moschip 2 port adapter", + .id_table = moschip_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 2, + .num_bulk_out = 2, + .num_ports = 2, + .open = mos7720_open, + .close = mos7720_close, + .throttle = mos7720_throttle, + .unthrottle = mos7720_unthrottle, + .attach = mos7720_startup, + .shutdown = mos7720_shutdown, + .ioctl = mos7720_ioctl, + .set_termios = mos7720_set_termios, + .write = mos7720_write, + .write_room = mos7720_write_room, + .chars_in_buffer = mos7720_chars_in_buffer, + .break_ctl = mos7720_break, + .read_bulk_callback = mos7720_bulk_in_callback, +}; + +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, +}; + +static int __init moschip7720_init(void) +{ + int retval; + + dbg("%s: Entering ..........", __FUNCTION__); + + /* Register with the usb serial */ + retval = usb_serial_register(&moschip7720_2port_driver); + if (retval) + goto failed_port_device_register; + + info(DRIVER_DESC " " DRIVER_VERSION); + + /* Register with the usb */ + retval = usb_register(&usb_driver); + if (retval) + goto failed_usb_register; + + return 0; + +failed_usb_register: + usb_serial_deregister(&moschip7720_2port_driver); + +failed_port_device_register: + return retval; +} + +static void __exit moschip7720_exit(void) +{ + usb_deregister(&usb_driver); + usb_serial_deregister(&moschip7720_2port_driver); +} + +module_init(moschip7720_init); +module_exit(moschip7720_exit); + +/* Module information */ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 021be39fe16..5b71962d035 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, } mos7840_port = mos7840_get_port_private(port); - tty = mos7840_port->port->tty; if (mos7840_port == NULL) return -1; + tty = mos7840_port->port->tty; + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index d29638daa98..4b5097fa48d 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,75 +1,713 @@ /* - * Sierra Wireless CDMA Wireless Serial USB driver - * - * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com> - * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de> - * - * 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. - */ + USB Driver for Sierra Wireless + + Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com> + + IMPORTANT DISCLAIMER: This driver is not commercially supported by + Sierra Wireless. Use at your own risk. + + This driver is free software; you can redistribute it and/or modify + it under the terms of Version 2 of the GNU General Public License as + published by the Free Software Foundation. + + Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> + Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> + + History: +*/ + +#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" +#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" #include <linux/kernel.h> -#include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/errno.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> + static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ - /* Following devices are supported in the airprime.c driver */ - /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */ - /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */ + + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ { } }; MODULE_DEVICE_TABLE(usb, id_table); +static struct usb_device_id id_table_1port [] = { + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ + { } +}; + +static struct usb_device_id id_table_3port [] = { + { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ + { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ + { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ + { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ + { } +}; + static struct usb_driver sierra_driver = { - .name = "sierra_wireless", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, + .name = "sierra", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + + +static int debug; + +/* per port private data */ +#define N_IN_URB 4 +#define N_OUT_URB 1 +#define IN_BUFLEN 4096 +#define OUT_BUFLEN 128 + +struct sierra_port_private { + /* Input endpoints and buffer for this port */ + struct urb *in_urbs[N_IN_URB]; + char in_buffer[N_IN_URB][IN_BUFLEN]; + /* Output endpoints and buffer for this port */ + struct urb *out_urbs[N_OUT_URB]; + char out_buffer[N_OUT_URB][OUT_BUFLEN]; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + + unsigned long tx_start_time[N_OUT_URB]; +}; + +static int sierra_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + portdata = usb_get_serial_port_data(port); + + if (port->tty) { + int val = 0; + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; + + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + } + + return 0; +} + +static void sierra_rx_throttle(struct usb_serial_port *port) +{ + dbg("%s", __FUNCTION__); +} + +static void sierra_rx_unthrottle(struct usb_serial_port *port) +{ + dbg("%s", __FUNCTION__); +} + +static void sierra_break_ctl(struct usb_serial_port *port, int break_state) +{ + /* Unfortunately, I don't know how to send a break */ + dbg("%s", __FUNCTION__); +} + +static void sierra_set_termios(struct usb_serial_port *port, + struct termios *old_termios) +{ + dbg("%s", __FUNCTION__); + + sierra_send_setup(port); +} + +static int sierra_tiocmget(struct usb_serial_port *port, struct file *file) +{ + unsigned int value; + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + value = ((portdata->rts_state) ? TIOCM_RTS : 0) | + ((portdata->dtr_state) ? TIOCM_DTR : 0) | + ((portdata->cts_state) ? TIOCM_CTS : 0) | + ((portdata->dsr_state) ? TIOCM_DSR : 0) | + ((portdata->dcd_state) ? TIOCM_CAR : 0) | + ((portdata->ri_state) ? TIOCM_RNG : 0); + + return value; +} + +static int sierra_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear) +{ + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + if (set & TIOCM_RTS) + portdata->rts_state = 1; + if (set & TIOCM_DTR) + portdata->dtr_state = 1; + + if (clear & TIOCM_RTS) + portdata->rts_state = 0; + if (clear & TIOCM_DTR) + portdata->dtr_state = 0; + return sierra_send_setup(port); +} + +static int sierra_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +/* Write */ +static int sierra_write(struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct sierra_port_private *portdata; + int i; + int left, todo; + struct urb *this_urb = NULL; /* spurious */ + int err; + + portdata = usb_get_serial_port_data(port); + + dbg("%s: write (%d chars)", __FUNCTION__, count); + + i = 0; + left = count; + for (i=0; left > 0 && i < N_OUT_URB; i++) { + todo = left; + if (todo > OUT_BUFLEN) + todo = OUT_BUFLEN; + + this_urb = portdata->out_urbs[i]; + if (this_urb->status == -EINPROGRESS) { + if (time_before(jiffies, + portdata->tx_start_time[i] + 10 * HZ)) + continue; + usb_unlink_urb(this_urb); + continue; + } + if (this_urb->status != 0) + dbg("usb_write %p failed (err=%d)", + this_urb, this_urb->status); + + dbg("%s: endpoint %d buf %d", __FUNCTION__, + usb_pipeendpoint(this_urb->pipe), i); + + /* send the data */ + memcpy (this_urb->transfer_buffer, buf, todo); + this_urb->transfer_buffer_length = todo; + + this_urb->dev = port->serial->dev; + err = usb_submit_urb(this_urb, GFP_ATOMIC); + if (err) { + dbg("usb_submit_urb %p (write bulk) failed " + "(%d, has %d)", this_urb, + err, this_urb->status); + continue; + } + portdata->tx_start_time[i] = jiffies; + buf += todo; + left -= todo; + } + + count -= left; + dbg("%s: wrote (did %d)", __FUNCTION__, count); + return count; +} + +static void sierra_indat_callback(struct urb *urb) +{ + int err; + int endpoint; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + + dbg("%s: %p", __FUNCTION__, urb); + + endpoint = usb_pipeendpoint(urb->pipe); + port = (struct usb_serial_port *) urb->context; + + if (urb->status) { + dbg("%s: nonzero status: %d on endpoint %02x.", + __FUNCTION__, urb->status, endpoint); + } else { + tty = port->tty; + if (urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } else { + dbg("%s: empty read urb received", __FUNCTION__); + } + + /* Resubmit urb so we continue receiving */ + if (port->open_count && urb->status != -ESHUTDOWN) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __FUNCTION__, err); + } + } + return; +} + +static void sierra_outdat_callback(struct urb *urb) +{ + struct usb_serial_port *port; + + dbg("%s", __FUNCTION__); + + port = (struct usb_serial_port *) urb->context; + + usb_serial_port_softint(port); +} + +static void sierra_instat_callback(struct urb *urb) +{ + int err; + struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + + dbg("%s", __FUNCTION__); + dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata); + + if (urb->status == 0) { + struct usb_ctrlrequest *req_pkt = + (struct usb_ctrlrequest *)urb->transfer_buffer; + + if (!req_pkt) { + dbg("%s: NULL req_pkt\n", __FUNCTION__); + return; + } + if ((req_pkt->bRequestType == 0xA1) && + (req_pkt->bRequest == 0x20)) { + int old_dcd_state; + unsigned char signals = *((unsigned char *) + urb->transfer_buffer + + sizeof(struct usb_ctrlrequest)); + + dbg("%s: signal x%x", __FUNCTION__, signals); + + old_dcd_state = portdata->dcd_state; + portdata->cts_state = 1; + portdata->dcd_state = ((signals & 0x01) ? 1 : 0); + portdata->dsr_state = ((signals & 0x02) ? 1 : 0); + portdata->ri_state = ((signals & 0x08) ? 1 : 0); + + if (port->tty && !C_CLOCAL(port->tty) && + old_dcd_state && !portdata->dcd_state) + tty_hangup(port->tty); + } else { + dbg("%s: type %x req %x", __FUNCTION__, + req_pkt->bRequestType,req_pkt->bRequest); + } + } else + dbg("%s: error %d", __FUNCTION__, urb->status); + + /* Resubmit urb so we continue receiving IRQ data */ + if (urb->status != -ESHUTDOWN) { + urb->dev = serial->dev; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dbg("%s: resubmit intr urb failed. (%d)", + __FUNCTION__, err); + } +} + +static int sierra_write_room(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i=0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && this_urb->status != -EINPROGRESS) + data_len += OUT_BUFLEN; + } + + dbg("%s: %d", __FUNCTION__, data_len); + return data_len; +} + +static int sierra_chars_in_buffer(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i=0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && this_urb->status == -EINPROGRESS) + data_len += this_urb->transfer_buffer_length; + } + dbg("%s: %d", __FUNCTION__, data_len); + return data_len; +} + +static int sierra_open(struct usb_serial_port *port, struct file *filp) +{ + struct sierra_port_private *portdata; + struct usb_serial *serial = port->serial; + int i, err; + struct urb *urb; + + portdata = usb_get_serial_port_data(port); + + dbg("%s", __FUNCTION__); + + /* Set some sane defaults */ + portdata->rts_state = 1; + portdata->dtr_state = 1; + + /* Reset low level data toggle and start reading from endpoints */ + for (i = 0; i < N_IN_URB; i++) { + urb = portdata->in_urbs[i]; + if (! urb) + continue; + if (urb->dev != serial->dev) { + dbg("%s: dev %p != %p", __FUNCTION__, + urb->dev, serial->dev); + continue; + } + + /* + * make sure endpoint data toggle is synchronized with the + * device + */ + usb_clear_halt(urb->dev, urb->pipe); + + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + dbg("%s: submit urb %d failed (%d) %d", + __FUNCTION__, i, err, + urb->transfer_buffer_length); + } + } + + /* Reset low level data toggle on out endpoints */ + for (i = 0; i < N_OUT_URB; i++) { + urb = portdata->out_urbs[i]; + if (! urb) + continue; + urb->dev = serial->dev; + /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), 0); */ + } + + port->tty->low_latency = 1; + + sierra_send_setup(port); + + return (0); +} + +static inline void stop_urb(struct urb *urb) +{ + if (urb && urb->status == -EINPROGRESS) + usb_kill_urb(urb); +} + +static void sierra_close(struct usb_serial_port *port, struct file *filp) +{ + int i; + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + portdata = usb_get_serial_port_data(port); + + portdata->rts_state = 0; + portdata->dtr_state = 0; + + if (serial->dev) { + sierra_send_setup(port); + + /* Stop reading/writing urbs */ + for (i = 0; i < N_IN_URB; i++) + stop_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) + stop_urb(portdata->out_urbs[i]); + } + port->tty = NULL; +} + +/* Helper functions used by sierra_setup_urbs */ +static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, char *buf, int len, + usb_complete_t callback) +{ + struct urb *urb; + + if (endpoint == -1) + return NULL; /* endpoint not needed */ + + urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ + if (urb == NULL) { + dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint); + return NULL; + } + + /* Fill URB using supplied data. */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + return urb; +} + +/* Setup urbs */ +static void sierra_setup_urbs(struct usb_serial *serial) +{ + int i,j; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ + for (j = 0; j < N_IN_URB; ++j) { + portdata->in_urbs[j] = sierra_setup_urb (serial, + port->bulk_in_endpointAddress, USB_DIR_IN, port, + portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback); + } + + /* outdat endpoints */ + for (j = 0; j < N_OUT_URB; ++j) { + portdata->out_urbs[j] = sierra_setup_urb (serial, + port->bulk_out_endpointAddress, USB_DIR_OUT, port, + portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback); + } + } +} + +static int sierra_startup(struct usb_serial *serial) +{ + int i, err; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) { + dbg("%s: kmalloc for sierra_port_private (%d) failed!.", + __FUNCTION__, i); + return (1); + } + + usb_set_serial_port_data(port, portdata); + + if (! port->interrupt_in_urb) + continue; + err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (err) + dbg("%s: submit irq_in urb failed %d", + __FUNCTION__, err); + } + + sierra_setup_urbs(serial); + + return (0); +} + +static void sierra_shutdown(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + /* Stop reading/writing urbs */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + for (j = 0; j < N_IN_URB; j++) + stop_urb(portdata->in_urbs[j]); + for (j = 0; j < N_OUT_URB; j++) + stop_urb(portdata->out_urbs[j]); + } + + /* Now free them */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + for (j = 0; j < N_IN_URB; j++) { + if (portdata->in_urbs[j]) { + usb_free_urb(portdata->in_urbs[j]); + portdata->in_urbs[j] = NULL; + } + } + for (j = 0; j < N_OUT_URB; j++) { + if (portdata->out_urbs[j]) { + usb_free_urb(portdata->out_urbs[j]); + portdata->out_urbs[j] = NULL; + } + } + } + + /* Now free per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + kfree(usb_get_serial_port_data(port)); + } +} + +static struct usb_serial_driver sierra_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "sierra1", + }, + .description = "Sierra USB modem (1 port)", + .id_table = id_table_1port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, }; -static struct usb_serial_driver sierra_device = { +static struct usb_serial_driver sierra_3port_device = { .driver = { - .owner = THIS_MODULE, - .name = "Sierra_Wireless", + .owner = THIS_MODULE, + .name = "sierra3", }, - .id_table = id_table, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 3, + .description = "Sierra USB modem (3 port)", + .id_table = id_table_3port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 3, + .num_bulk_out = 3, + .num_ports = 3, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, }; +/* Functions used by new usb-serial code. */ static int __init sierra_init(void) { int retval; - - retval = usb_serial_register(&sierra_device); + retval = usb_serial_register(&sierra_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&sierra_3port_device); if (retval) - return retval; + goto failed_3port_device_register; + + retval = usb_register(&sierra_driver); if (retval) - usb_serial_deregister(&sierra_device); + goto failed_driver_register; + + info(DRIVER_DESC ": " DRIVER_VERSION); + + return 0; + +failed_driver_register: + usb_serial_deregister(&sierra_3port_device); +failed_3port_device_register: + usb_serial_deregister(&sierra_1port_device); +failed_1port_device_register: return retval; } static void __exit sierra_exit(void) { - usb_deregister(&sierra_driver); - usb_serial_deregister(&sierra_device); + usb_deregister (&sierra_driver); + usb_serial_deregister(&sierra_1port_device); + usb_serial_deregister(&sierra_3port_device); } module_init(sierra_init); module_exit(sierra_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); + +#ifdef CONFIG_USB_DEBUG +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug messages"); +#endif + diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c9a8d50106d..efb047f431e 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE), -UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, +/* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */ +UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200, "Mitsumi", "USB FDD", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -182,6 +183,20 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by Bardur Arantsson <bardur@scientician.net> */ +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, + "Nokia", + "6131", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + +/* Reported by Alex Corcoles <alex@corcoles.net> */ +UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, + "Nokia", + "6234", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", @@ -1221,7 +1236,7 @@ UNUSUAL_DEV( 0x0e21, 0x0520, 0x0100, 0x0100, "Cowon Systems", "iAUDIO M5", US_SC_DEVICE, US_PR_BULK, NULL, - 0 ), + US_FL_NEED_OVERRIDE ), /* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, @@ -1294,8 +1309,10 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. + * Devices with bcd > 110 seem to not need it while those + * with bcd < 110 appear to need it. */ -UNUSUAL_DEV( 0x1019, 0x0c55, 0x0110, 0x0110, +UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110, "Desknote", "UCR-61S2B", US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init, diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index daaa486159c..7a43020fa58 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -701,7 +701,6 @@ config FB_NVIDIA depends on FB && PCI select I2C_ALGOBIT if FB_NVIDIA_I2C select I2C if FB_NVIDIA_I2C - select FB_DDC if FB_NVIDIA_I2C select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index b77b3092392..e815b354c09 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -406,7 +406,7 @@ static struct { { PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, 135, ATI_CHIP_264LTPRO }, { PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, 135, ATI_CHIP_264LTPRO }, { PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, - { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO }, + { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1024x768 }, { PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO }, { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL }, diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 67675452009..869725a13c2 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -139,7 +139,13 @@ void radeon_delete_i2c_busses(struct radeonfb_info *rinfo) int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid) { - u8 *edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter); + u32 reg = rinfo->i2c[conn-1].ddc_reg; + u8 *edid; + + OUTREG(reg, INREG(reg) & + ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT)); + + edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter); if (out_edid) *out_edid = edid; diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 2ebbfd95145..d07ecb53c68 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -111,7 +111,7 @@ static struct backlight_properties corgibl_data = { .update_status = corgibl_set_intensity, }; -static int __init corgibl_probe(struct platform_device *pdev) +static int corgibl_probe(struct platform_device *pdev) { struct corgibl_machinfo *machinfo = pdev->dev.platform_data; @@ -166,4 +166,4 @@ module_exit(corgibl_exit); MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); MODULE_DESCRIPTION("Corgi Backlight Driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index fe1488374f6..e3993213d10 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -19,7 +19,7 @@ #include <linux/backlight.h> #include <asm/cpu/dac.h> -#include <asm/hp6xx/hp6xx.h> +#include <asm/hp6xx.h> #include <asm/hd64461.h> #define HP680_MAX_INTENSITY 255 diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 8cc6c0e2d27..04c6d928189 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -415,13 +415,15 @@ static int __init init_control(struct fb_info_control *p) full = p->total_vram == 0x400000; /* Try to pick a video mode out of NVRAM if we have one. */ +#ifdef CONFIG_NVRAM if (default_cmode == CMODE_NVRAM){ cmode = nvram_read_byte(NV_CMODE); if(cmode < CMODE_8 || cmode > CMODE_32) cmode = CMODE_8; } else +#endif cmode=default_cmode; - +#ifdef CONFIG_NVRAM if (default_vmode == VMODE_NVRAM) { vmode = nvram_read_byte(NV_VMODE); if (vmode < 1 || vmode > VMODE_MAX || @@ -432,7 +434,9 @@ static int __init init_control(struct fb_info_control *p) if (control_mac_modes[vmode - 1].m[full] < cmode) vmode = VMODE_640_480_60; } - } else { + } else +#endif + { vmode=default_vmode; if (control_mac_modes[vmode - 1].m[full] < cmode) { if (cmode > CMODE_8) diff --git a/drivers/video/fb_ddc.c b/drivers/video/fb_ddc.c index 3aa6ebf68f1..f836137a0ed 100644 --- a/drivers/video/fb_ddc.c +++ b/drivers/video/fb_ddc.c @@ -20,26 +20,26 @@ static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter) { unsigned char start = 0x0; + unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); struct i2c_msg msgs[] = { { .addr = DDC_ADDR, + .flags = 0, .len = 1, .buf = &start, }, { .addr = DDC_ADDR, .flags = I2C_M_RD, .len = EDID_LENGTH, + .buf = buf, } }; - unsigned char *buf; - buf = kmalloc(EDID_LENGTH, GFP_KERNEL); if (!buf) { dev_warn(&adapter->dev, "unable to allocate memory for EDID " "block.\n"); return NULL; } - msgs[1].buf = buf; if (i2c_transfer(adapter, msgs, 2) == 2) return buf; diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 3afb472763c..3dc49424dc7 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -29,7 +29,6 @@ #include <asm/io.h> #include <asm/hd64461.h> #include <asm/cpu/dac.h> -#include <asm/hp6xx/hp6xx.h> #define WIDTH 640 diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 67f384f8675..e6df492c22a 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -573,3 +573,10 @@ int __init igafb_setup(char *options) module_init(igafb_init); MODULE_LICENSE("GPL"); +static struct pci_device_id igafb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, igafb_pci_tbl); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index eeeeff9a09e..a95836839e1 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -161,7 +161,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, return 1; /* Find the bridge device. It is always 0:0.0 */ - if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) { + if (!(bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)))) { ERR_MSG("cannot find bridge device\n"); return 1; } @@ -169,6 +169,8 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, /* Get the fb aperture size and "stolen" memory amount. */ tmp = 0; pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); + pci_dev_put(bridge_dev); + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_915G: case PCI_DEVICE_ID_INTEL_915GM: @@ -662,7 +664,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) int index = dinfo->pll_index; DBG_MSG("intelfbhw_print_hw_state\n"); - if (!hw || !dinfo) + if (!hw) return; /* Read in as much of the HW state as possible. */ printk("hw state dump start\n"); diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index 9ed640d3572..ea426115c6f 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c @@ -145,12 +145,18 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, if (par->Architecture >= NV_ARCH_40) { pll = NV_RD32(par->PMC, 0x4020); - P = (pll >> 16) & 0x03; + P = (pll >> 16) & 0x07; pll = NV_RD32(par->PMC, 0x4024); M = pll & 0xFF; N = (pll >> 8) & 0xFF; - MB = (pll >> 16) & 0xFF; - NB = (pll >> 24) & 0xFF; + if (((par->Chipset & 0xfff0) == 0x0290) || + ((par->Chipset & 0xfff0) == 0x0390)) { + MB = 1; + NB = 1; + } else { + MB = (pll >> 16) & 0xFF; + NB = (pll >> 24) & 0xFF; + } *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; pll = NV_RD32(par->PMC, 0x4000); diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index e48de3c9fd1..19eef3a0902 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -160,12 +160,51 @@ void nvidia_delete_i2c_busses(struct nvidia_par *par) } +static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .len = 1, + .buf = &start, + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + if (!chan->par) + return NULL; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) { struct nvidia_par *par = info->par; - u8 *edid; - - edid = fb_ddc_read(&par->chan[conn - 1].adapter); + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]); + if (edid) + break; + } if (!edid && conn == 1) { /* try to get from firmware */ diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index a18a9aebf05..eab3e282a4d 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -262,7 +262,7 @@ static void nv10GetConfig(struct nvidia_par *par) #endif dev = pci_find_slot(0, 1); - if ((par->Chipset && 0xffff) == 0x01a0) { + if ((par->Chipset & 0xffff) == 0x01a0) { int amt = 0; pci_read_config_dword(dev, 0x7c, &amt); @@ -359,6 +359,7 @@ int NVCommonSetup(struct fb_info *info) case 0x0186: case 0x0187: case 0x018D: + case 0x0228: case 0x0286: case 0x028C: case 0x0316: @@ -382,6 +383,10 @@ int NVCommonSetup(struct fb_info *info) case 0x034C: case 0x0160: case 0x0166: + case 0x0169: + case 0x016B: + case 0x016C: + case 0x016D: case 0x00C8: case 0x00CC: case 0x0144: @@ -639,12 +644,23 @@ int NVCommonSetup(struct fb_info *info) par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1; par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033; - printk("Panel size is %i x %i\n", par->fpWidth, par->fpHeight); + printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight); } if (monA) info->monspecs = *monA; + if (!par->FlatPanel || !par->twoHeads) + par->FPDither = 0; + + par->LVDS = 0; + if (par->FlatPanel && par->twoHeads) { + NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004); + if (par->PRAMDAC0[0x08b4] & 1) + par->LVDS = 1; + printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS"); + } + kfree(edidA); kfree(edidB); done: diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index acdc2669340..86e65dea60d 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h @@ -129,6 +129,7 @@ struct nvidia_par { int fpHeight; int PanelTweak; int paneltweak; + int LVDS; int pm_state; u32 crtcSync_read; u32 fpSyncs; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index eb24107bcc8..538e947610e 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1160,20 +1160,20 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info) case 0x0340: /* GeForceFX 5700 */ arch = NV_ARCH_30; break; - case 0x0040: - case 0x00C0: - case 0x0120: + case 0x0040: /* GeForce 6800 */ + case 0x00C0: /* GeForce 6800 */ + case 0x0120: /* GeForce 6800 */ case 0x0130: - case 0x0140: - case 0x0160: - case 0x01D0: - case 0x0090: - case 0x0210: - case 0x0220: + case 0x0140: /* GeForce 6600 */ + case 0x0160: /* GeForce 6200 */ + case 0x01D0: /* GeForce 7200, 7300, 7400 */ + case 0x0090: /* GeForce 7800 */ + case 0x0210: /* GeForce 6800 */ + case 0x0220: /* GeForce 6200 */ case 0x0230: - case 0x0240: - case 0x0290: - case 0x0390: + case 0x0240: /* GeForce 6100 */ + case 0x0290: /* GeForce 7900 */ + case 0x0390: /* GeForce 7600 */ arch = NV_ARCH_40; break; case 0x0020: /* TNT, TNT2 */ diff --git a/drivers/video/offb.c b/drivers/video/offb.c index bad0e98fb3b..9a40bbecf76 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -157,7 +157,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); break; case cmap_gxt2000: - out_le32((unsigned __iomem *) par->cmap_adr + regno, + out_le32(((unsigned __iomem *) par->cmap_adr) + regno, (red << 16 | green << 8 | blue)); break; } @@ -213,7 +213,7 @@ static int offb_blank(int blank, struct fb_info *info) out_le32(par->cmap_adr + 0xb4, 0); break; case cmap_gxt2000: - out_le32((unsigned __iomem *) par->cmap_adr + i, + out_le32(((unsigned __iomem *) par->cmap_adr) + i, 0); break; } @@ -226,13 +226,23 @@ static int offb_blank(int blank, struct fb_info *info) static void __iomem *offb_map_reg(struct device_node *np, int index, unsigned long offset, unsigned long size) { - struct resource r; - - 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); + const u32 *addrp; + u64 asize, taddr; + unsigned int flags; + + addrp = of_get_pci_address(np, index, &asize, &flags); + if (addrp == NULL) + addrp = of_get_address(np, index, &asize, &flags); + if (addrp == NULL) + return NULL; + if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + return NULL; + if ((offset + size) > asize) + return NULL; + taddr = of_translate_address(np, addrp); + if (taddr == OF_BAD_ADDR) + return NULL; + return ioremap(taddr + offset, size); } static void __init offb_init_fb(const char *name, const char *full_name, @@ -289,7 +299,6 @@ 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 (dp && !strncmp(name, "ATY,Rage128", 11)) { par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); if (par->cmap_adr) @@ -313,7 +322,8 @@ static void __init offb_init_fb(const char *name, const char *full_name, ioremap(base + 0x7ff000, 0x1000) + 0xcc0; par->cmap_data = par->cmap_adr + 1; par->cmap_type = cmap_m64; - } else if (dp && device_is_compatible(dp, "pci1014,b7")) { + } else if (dp && (device_is_compatible(dp, "pci1014,b7") || + device_is_compatible(dp, "pci1014,21c"))) { par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); if (par->cmap_adr) par->cmap_type = cmap_gxt2000; @@ -433,7 +443,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) pp = get_property(dp, "linux,bootx-linebytes", &len); if (pp == NULL) pp = get_property(dp, "linebytes", &len); - if (pp && len == sizeof(u32)) + if (pp && len == sizeof(u32) && (*pp != 0xffffffffu)) pitch = *pp; else pitch = width * ((depth + 7) / 8); @@ -496,7 +506,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) 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); + no_real_node ? NULL : dp); } } diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 983be3ec234..fdb33cd21a2 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -339,11 +339,12 @@ static int __devinit platinum_init_fb(struct fb_info *info) sense = read_platinum_sense(pinfo); printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense); - if (default_vmode == VMODE_NVRAM) { +#ifdef CONFIG_NVRAM default_vmode = nvram_read_byte(NV_VMODE); if (default_vmode <= 0 || default_vmode > VMODE_MAX || !platinum_reg_init[default_vmode-1]) +#endif default_vmode = VMODE_CHOOSE; } if (default_vmode == VMODE_CHOOSE) { @@ -351,8 +352,10 @@ static int __devinit platinum_init_fb(struct fb_info *info) } if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; +#ifdef CONFIG_NVRAM if (default_cmode == CMODE_NVRAM) default_cmode = nvram_read_byte(NV_CMODE); +#endif if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; /* diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c index 7d9453c91a4..f29e66e2d77 100644 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ b/drivers/video/pnx4008/pnxrgbfb.c @@ -154,7 +154,8 @@ static int __devinit rgbfb_probe(struct platform_device *pdev) goto err1; } - if (!fb_get_options("pnxrgbfb", &option) && !strcmp(option, "nocursor")) + if (!fb_get_options("pnxrgbfb", &option) && option && + !strcmp(option, "nocursor")) rgbfb_ops.fb_cursor = no_cursor; info->node = -1; @@ -191,7 +192,7 @@ err: static struct platform_driver rgbfb_driver = { .driver = { - .name = "rgbfb", + .name = "pnx4008-rgbfb", }, .probe = rgbfb_probe, .remove = rgbfb_remove, diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c index 51f0ecc2a51..d23bf0d659b 100644 --- a/drivers/video/pnx4008/sdum.c +++ b/drivers/video/pnx4008/sdum.c @@ -848,7 +848,7 @@ static int sdum_remove(struct platform_device *pdev) static struct platform_driver sdum_driver = { .driver = { - .name = "sdum", + .name = "pnx4008-sdum", }, .probe = sdum_probe, .remove = sdum_remove, diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 47f27924a7d..06fc19a6119 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -284,7 +284,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense); /* Try to pick a video mode out of NVRAM if we have one. */ -#ifndef CONFIG_MAC +#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM) if (default_vmode == VMODE_NVRAM) { default_vmode = nvram_read_byte(NV_VMODE); if (default_vmode <= 0 @@ -297,7 +297,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) default_vmode = mac_map_monitor_sense(p->sense); if (!valkyrie_reg_init[default_vmode - 1]) default_vmode = VMODE_640_480_67; -#ifndef CONFIG_MAC +#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM) if (default_cmode == CMODE_NVRAM) default_cmode = nvram_read_byte(NV_CMODE); #endif diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 27c9d05d03e..c287a9ae4fd 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -2,7 +2,6 @@ menu "Dallas's 1-wire bus" config W1 tristate "Dallas's 1-wire support" - depends on CONNECTOR ---help--- Dallas' 1-wire bus is useful to connect slow 1-pin devices such as iButtons and thermal sensors. diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index 2788b8ca9bb..6f9d880ab2e 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -215,6 +215,8 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi return 0; err_out_free_device: + if (dev->virt_addr) + iounmap(dev->virt_addr); kfree(dev); return err; |