diff options
51 files changed, 2491 insertions, 734 deletions
diff --git a/Documentation/pci.txt b/Documentation/pci.txt index bb7bd27d4682..d2c2e6e2b224 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt | |||
| @@ -123,7 +123,7 @@ initialization with a pointer to a structure describing the driver | |||
| 123 | 123 | ||
| 124 | 124 | ||
| 125 | The ID table is an array of struct pci_device_id entries ending with an | 125 | The ID table is an array of struct pci_device_id entries ending with an |
| 126 | all-zero entry; use of the macro DECLARE_PCI_DEVICE_TABLE is the preferred | 126 | all-zero entry; use of the macro DEFINE_PCI_DEVICE_TABLE is the preferred |
| 127 | method of declaring the table. Each entry consists of: | 127 | method of declaring the table. Each entry consists of: |
| 128 | 128 | ||
| 129 | vendor,device Vendor and device ID to match (or PCI_ANY_ID) | 129 | vendor,device Vendor and device ID to match (or PCI_ANY_ID) |
| @@ -193,7 +193,7 @@ Tips on when/where to use the above attributes: | |||
| 193 | o Do not mark the struct pci_driver. | 193 | o Do not mark the struct pci_driver. |
| 194 | 194 | ||
| 195 | o The ID table array should be marked __devinitconst; this is done | 195 | o The ID table array should be marked __devinitconst; this is done |
| 196 | automatically if the table is declared with DECLARE_PCI_DEVICE_TABLE(). | 196 | automatically if the table is declared with DEFINE_PCI_DEVICE_TABLE(). |
| 197 | 197 | ||
| 198 | o The probe() and remove() functions should be marked __devinit | 198 | o The probe() and remove() functions should be marked __devinit |
| 199 | and __devexit respectively. All initialization functions | 199 | and __devexit respectively. All initialization functions |
diff --git a/Documentation/scheduler/sched-stats.txt b/Documentation/scheduler/sched-stats.txt index 442e14d35dea..01e69404ee5e 100644 --- a/Documentation/scheduler/sched-stats.txt +++ b/Documentation/scheduler/sched-stats.txt | |||
| @@ -142,7 +142,7 @@ of idleness (idle, busy, and newly idle): | |||
| 142 | 142 | ||
| 143 | /proc/<pid>/schedstat | 143 | /proc/<pid>/schedstat |
| 144 | ---------------- | 144 | ---------------- |
| 145 | schedstats also adds a new /proc/<pid/schedstat file to include some of | 145 | schedstats also adds a new /proc/<pid>/schedstat file to include some of |
| 146 | the same information on a per-process level. There are three fields in | 146 | the same information on a per-process level. There are three fields in |
| 147 | this file correlating for that process to: | 147 | this file correlating for that process to: |
| 148 | 1) time spent on the cpu | 148 | 1) time spent on the cpu |
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 8fc4fe4e38f1..589ac6f65b9a 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c | |||
| @@ -1620,14 +1620,8 @@ static int __init rc_init_drivers(void) | |||
| 1620 | 1620 | ||
| 1621 | static void rc_release_drivers(void) | 1621 | static void rc_release_drivers(void) |
| 1622 | { | 1622 | { |
| 1623 | unsigned long flags; | ||
| 1624 | |||
| 1625 | spin_lock_irqsave(&riscom_lock, flags); | ||
| 1626 | |||
| 1627 | tty_unregister_driver(riscom_driver); | 1623 | tty_unregister_driver(riscom_driver); |
| 1628 | put_tty_driver(riscom_driver); | 1624 | put_tty_driver(riscom_driver); |
| 1629 | |||
| 1630 | spin_unlock_irqrestore(&riscom_lock, flags); | ||
| 1631 | } | 1625 | } |
| 1632 | 1626 | ||
| 1633 | #ifndef MODULE | 1627 | #ifndef MODULE |
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 92583cd4bffd..6e72fd31184d 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c | |||
| @@ -184,6 +184,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) | |||
| 184 | gc->direction_output = pca953x_gpio_direction_output; | 184 | gc->direction_output = pca953x_gpio_direction_output; |
| 185 | gc->get = pca953x_gpio_get_value; | 185 | gc->get = pca953x_gpio_get_value; |
| 186 | gc->set = pca953x_gpio_set_value; | 186 | gc->set = pca953x_gpio_set_value; |
| 187 | gc->can_sleep = 1; | ||
| 187 | 188 | ||
| 188 | gc->base = chip->gpio_start; | 189 | gc->base = chip->gpio_start; |
| 189 | gc->ngpio = gpios; | 190 | gc->ngpio = gpios; |
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index dd22d91f8b39..c972e5d03a3f 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #if defined(CONFIG_MACH_JAZZ) | 17 | #if defined(CONFIG_MACH_JAZZ) |
| 18 | #include "i8042-jazzio.h" | 18 | #include "i8042-jazzio.h" |
| 19 | #elif defined(CONFIG_SGI_IP22) | 19 | #elif defined(CONFIG_SGI_HAS_I8042) |
| 20 | #include "i8042-ip22io.h" | 20 | #include "i8042-ip22io.h" |
| 21 | #elif defined(CONFIG_PPC) | 21 | #elif defined(CONFIG_PPC) |
| 22 | #include "i8042-ppcio.h" | 22 | #include "i8042-ppcio.h" |
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 831aed9c56ff..c14dacdacfac 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
| @@ -1045,7 +1045,8 @@ void bitmap_daemon_work(struct bitmap *bitmap) | |||
| 1045 | if (bitmap == NULL) | 1045 | if (bitmap == NULL) |
| 1046 | return; | 1046 | return; |
| 1047 | if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) | 1047 | if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) |
| 1048 | return; | 1048 | goto done; |
| 1049 | |||
| 1049 | bitmap->daemon_lastrun = jiffies; | 1050 | bitmap->daemon_lastrun = jiffies; |
| 1050 | if (bitmap->allclean) { | 1051 | if (bitmap->allclean) { |
| 1051 | bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; | 1052 | bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; |
| @@ -1142,6 +1143,7 @@ void bitmap_daemon_work(struct bitmap *bitmap) | |||
| 1142 | } | 1143 | } |
| 1143 | } | 1144 | } |
| 1144 | 1145 | ||
| 1146 | done: | ||
| 1145 | if (bitmap->allclean == 0) | 1147 | if (bitmap->allclean == 0) |
| 1146 | bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ; | 1148 | bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ; |
| 1147 | } | 1149 | } |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 827824a9f3e9..ccbbf63727cc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -5149,7 +5149,7 @@ static int md_seq_show(struct seq_file *seq, void *v) | |||
| 5149 | if (mddev->ro==1) | 5149 | if (mddev->ro==1) |
| 5150 | seq_printf(seq, " (read-only)"); | 5150 | seq_printf(seq, " (read-only)"); |
| 5151 | if (mddev->ro==2) | 5151 | if (mddev->ro==2) |
| 5152 | seq_printf(seq, "(auto-read-only)"); | 5152 | seq_printf(seq, " (auto-read-only)"); |
| 5153 | seq_printf(seq, " %s", mddev->pers->name); | 5153 | seq_printf(seq, " %s", mddev->pers->name); |
| 5154 | } | 5154 | } |
| 5155 | 5155 | ||
diff --git a/drivers/memstick/Kconfig b/drivers/memstick/Kconfig index 1093fdb07297..f0ca41c20323 100644 --- a/drivers/memstick/Kconfig +++ b/drivers/memstick/Kconfig | |||
| @@ -8,7 +8,7 @@ menuconfig MEMSTICK | |||
| 8 | Sony MemoryStick is a proprietary storage/extension card protocol. | 8 | Sony MemoryStick is a proprietary storage/extension card protocol. |
| 9 | 9 | ||
| 10 | If you want MemoryStick support, you should say Y here and also | 10 | If you want MemoryStick support, you should say Y here and also |
| 11 | to the specific driver for your MMC interface. | 11 | to the specific driver for your MemoryStick interface. |
| 12 | 12 | ||
| 13 | if MEMSTICK | 13 | if MEMSTICK |
| 14 | 14 | ||
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index bba467fe4bce..de80dba12f9b 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
| 19 | 19 | ||
| 20 | #define DRIVER_NAME "memstick" | 20 | #define DRIVER_NAME "memstick" |
| 21 | #define DRIVER_VERSION "0.2" | ||
| 22 | 21 | ||
| 23 | static unsigned int cmd_retries = 3; | 22 | static unsigned int cmd_retries = 3; |
| 24 | module_param(cmd_retries, uint, 0644); | 23 | module_param(cmd_retries, uint, 0644); |
| @@ -236,7 +235,7 @@ int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq) | |||
| 236 | rc = host->card->next_request(host->card, mrq); | 235 | rc = host->card->next_request(host->card, mrq); |
| 237 | 236 | ||
| 238 | if (!rc) | 237 | if (!rc) |
| 239 | host->retries = cmd_retries; | 238 | host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1; |
| 240 | else | 239 | else |
| 241 | *mrq = NULL; | 240 | *mrq = NULL; |
| 242 | 241 | ||
| @@ -271,7 +270,7 @@ void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, | |||
| 271 | mrq->data_dir = READ; | 270 | mrq->data_dir = READ; |
| 272 | 271 | ||
| 273 | mrq->sg = *sg; | 272 | mrq->sg = *sg; |
| 274 | mrq->io_type = MEMSTICK_IO_SG; | 273 | mrq->long_data = 1; |
| 275 | 274 | ||
| 276 | if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) | 275 | if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) |
| 277 | mrq->need_card_int = 1; | 276 | mrq->need_card_int = 1; |
| @@ -306,7 +305,7 @@ void memstick_init_req(struct memstick_request *mrq, unsigned char tpc, | |||
| 306 | if (mrq->data_dir == WRITE) | 305 | if (mrq->data_dir == WRITE) |
| 307 | memcpy(mrq->data, buf, mrq->data_len); | 306 | memcpy(mrq->data, buf, mrq->data_len); |
| 308 | 307 | ||
| 309 | mrq->io_type = MEMSTICK_IO_VAL; | 308 | mrq->long_data = 0; |
| 310 | 309 | ||
| 311 | if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) | 310 | if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) |
| 312 | mrq->need_card_int = 1; | 311 | mrq->need_card_int = 1; |
| @@ -561,6 +560,31 @@ void memstick_free_host(struct memstick_host *host) | |||
| 561 | } | 560 | } |
| 562 | EXPORT_SYMBOL(memstick_free_host); | 561 | EXPORT_SYMBOL(memstick_free_host); |
| 563 | 562 | ||
| 563 | /** | ||
| 564 | * memstick_suspend_host - notify bus driver of host suspension | ||
| 565 | * @host - host to use | ||
| 566 | */ | ||
| 567 | void memstick_suspend_host(struct memstick_host *host) | ||
| 568 | { | ||
| 569 | mutex_lock(&host->lock); | ||
| 570 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); | ||
| 571 | mutex_unlock(&host->lock); | ||
| 572 | } | ||
| 573 | EXPORT_SYMBOL(memstick_suspend_host); | ||
| 574 | |||
| 575 | /** | ||
| 576 | * memstick_resume_host - notify bus driver of host resumption | ||
| 577 | * @host - host to use | ||
| 578 | */ | ||
| 579 | void memstick_resume_host(struct memstick_host *host) | ||
| 580 | { | ||
| 581 | mutex_lock(&host->lock); | ||
| 582 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); | ||
| 583 | mutex_unlock(&host->lock); | ||
| 584 | memstick_detect_change(host); | ||
| 585 | } | ||
| 586 | EXPORT_SYMBOL(memstick_resume_host); | ||
| 587 | |||
| 564 | int memstick_register_driver(struct memstick_driver *drv) | 588 | int memstick_register_driver(struct memstick_driver *drv) |
| 565 | { | 589 | { |
| 566 | drv->driver.bus = &memstick_bus_type; | 590 | drv->driver.bus = &memstick_bus_type; |
| @@ -611,4 +635,3 @@ module_exit(memstick_exit); | |||
| 611 | MODULE_AUTHOR("Alex Dubov"); | 635 | MODULE_AUTHOR("Alex Dubov"); |
| 612 | MODULE_LICENSE("GPL"); | 636 | MODULE_LICENSE("GPL"); |
| 613 | MODULE_DESCRIPTION("Sony MemoryStick core driver"); | 637 | MODULE_DESCRIPTION("Sony MemoryStick core driver"); |
| 614 | MODULE_VERSION(DRIVER_VERSION); | ||
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 423ad8cf4bb9..1d637e4561d3 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c | |||
| @@ -16,10 +16,10 @@ | |||
| 16 | #include <linux/idr.h> | 16 | #include <linux/idr.h> |
| 17 | #include <linux/hdreg.h> | 17 | #include <linux/hdreg.h> |
| 18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
| 19 | #include <linux/delay.h> | ||
| 19 | #include <linux/memstick.h> | 20 | #include <linux/memstick.h> |
| 20 | 21 | ||
| 21 | #define DRIVER_NAME "mspro_block" | 22 | #define DRIVER_NAME "mspro_block" |
| 22 | #define DRIVER_VERSION "0.2" | ||
| 23 | 23 | ||
| 24 | static int major; | 24 | static int major; |
| 25 | module_param(major, int, 0644); | 25 | module_param(major, int, 0644); |
| @@ -110,6 +110,17 @@ struct mspro_mbr { | |||
| 110 | unsigned int sectors_per_partition; | 110 | unsigned int sectors_per_partition; |
| 111 | } __attribute__((packed)); | 111 | } __attribute__((packed)); |
| 112 | 112 | ||
| 113 | struct mspro_specfile { | ||
| 114 | char name[8]; | ||
| 115 | char ext[3]; | ||
| 116 | unsigned char attr; | ||
| 117 | unsigned char reserved[10]; | ||
| 118 | unsigned short time; | ||
| 119 | unsigned short date; | ||
| 120 | unsigned short cluster; | ||
| 121 | unsigned int size; | ||
| 122 | } __attribute__((packed)); | ||
| 123 | |||
| 113 | struct mspro_devinfo { | 124 | struct mspro_devinfo { |
| 114 | unsigned short cylinders; | 125 | unsigned short cylinders; |
| 115 | unsigned short heads; | 126 | unsigned short heads; |
| @@ -293,6 +304,20 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, | |||
| 293 | dev_attr); | 304 | dev_attr); |
| 294 | struct mspro_sys_info *x_sys = x_attr->data; | 305 | struct mspro_sys_info *x_sys = x_attr->data; |
| 295 | ssize_t rc = 0; | 306 | ssize_t rc = 0; |
| 307 | int date_tz = 0, date_tz_f = 0; | ||
| 308 | |||
| 309 | if (x_sys->assembly_date[0] > 0x80U) { | ||
| 310 | date_tz = (~x_sys->assembly_date[0]) + 1; | ||
| 311 | date_tz_f = date_tz & 3; | ||
| 312 | date_tz >>= 2; | ||
| 313 | date_tz = -date_tz; | ||
| 314 | date_tz_f *= 15; | ||
| 315 | } else if (x_sys->assembly_date[0] < 0x80U) { | ||
| 316 | date_tz = x_sys->assembly_date[0]; | ||
| 317 | date_tz_f = date_tz & 3; | ||
| 318 | date_tz >>= 2; | ||
| 319 | date_tz_f *= 15; | ||
| 320 | } | ||
| 296 | 321 | ||
| 297 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n", | 322 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n", |
| 298 | x_sys->class); | 323 | x_sys->class); |
| @@ -305,8 +330,8 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, | |||
| 305 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n", | 330 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n", |
| 306 | be16_to_cpu(x_sys->page_size)); | 331 | be16_to_cpu(x_sys->page_size)); |
| 307 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " | 332 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " |
| 308 | "%d %04u-%02u-%02u %02u:%02u:%02u\n", | 333 | "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", |
| 309 | x_sys->assembly_date[0], | 334 | date_tz, date_tz_f, |
| 310 | be16_to_cpu(*(unsigned short *) | 335 | be16_to_cpu(*(unsigned short *) |
| 311 | &x_sys->assembly_date[1]), | 336 | &x_sys->assembly_date[1]), |
| 312 | x_sys->assembly_date[3], x_sys->assembly_date[4], | 337 | x_sys->assembly_date[3], x_sys->assembly_date[4], |
| @@ -398,6 +423,41 @@ static ssize_t mspro_block_attr_show_mbr(struct device *dev, | |||
| 398 | return rc; | 423 | return rc; |
| 399 | } | 424 | } |
| 400 | 425 | ||
| 426 | static ssize_t mspro_block_attr_show_specfile(struct device *dev, | ||
| 427 | struct device_attribute *attr, | ||
| 428 | char *buffer) | ||
| 429 | { | ||
| 430 | struct mspro_sys_attr *x_attr = container_of(attr, | ||
| 431 | struct mspro_sys_attr, | ||
| 432 | dev_attr); | ||
| 433 | struct mspro_specfile *x_spfile = x_attr->data; | ||
| 434 | char name[9], ext[4]; | ||
| 435 | ssize_t rc = 0; | ||
| 436 | |||
| 437 | memcpy(name, x_spfile->name, 8); | ||
| 438 | name[8] = 0; | ||
| 439 | memcpy(ext, x_spfile->ext, 3); | ||
| 440 | ext[3] = 0; | ||
| 441 | |||
| 442 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name); | ||
| 443 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext); | ||
| 444 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n", | ||
| 445 | x_spfile->attr); | ||
| 446 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n", | ||
| 447 | x_spfile->time >> 11, | ||
| 448 | (x_spfile->time >> 5) & 0x3f, | ||
| 449 | (x_spfile->time & 0x1f) * 2); | ||
| 450 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n", | ||
| 451 | (x_spfile->date >> 9) + 1980, | ||
| 452 | (x_spfile->date >> 5) & 0xf, | ||
| 453 | x_spfile->date & 0x1f); | ||
| 454 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n", | ||
| 455 | x_spfile->cluster); | ||
| 456 | rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n", | ||
| 457 | x_spfile->size); | ||
| 458 | return rc; | ||
| 459 | } | ||
| 460 | |||
| 401 | static ssize_t mspro_block_attr_show_devinfo(struct device *dev, | 461 | static ssize_t mspro_block_attr_show_devinfo(struct device *dev, |
| 402 | struct device_attribute *attr, | 462 | struct device_attribute *attr, |
| 403 | char *buffer) | 463 | char *buffer) |
| @@ -430,6 +490,9 @@ static sysfs_show_t mspro_block_attr_show(unsigned char tag) | |||
| 430 | return mspro_block_attr_show_modelname; | 490 | return mspro_block_attr_show_modelname; |
| 431 | case MSPRO_BLOCK_ID_MBR: | 491 | case MSPRO_BLOCK_ID_MBR: |
| 432 | return mspro_block_attr_show_mbr; | 492 | return mspro_block_attr_show_mbr; |
| 493 | case MSPRO_BLOCK_ID_SPECFILEVALUES1: | ||
| 494 | case MSPRO_BLOCK_ID_SPECFILEVALUES2: | ||
| 495 | return mspro_block_attr_show_specfile; | ||
| 433 | case MSPRO_BLOCK_ID_DEVINFO: | 496 | case MSPRO_BLOCK_ID_DEVINFO: |
| 434 | return mspro_block_attr_show_devinfo; | 497 | return mspro_block_attr_show_devinfo; |
| 435 | default: | 498 | default: |
| @@ -629,7 +692,7 @@ static void mspro_block_process_request(struct memstick_dev *card, | |||
| 629 | param.system = msb->system; | 692 | param.system = msb->system; |
| 630 | param.data_count = cpu_to_be16(page_count); | 693 | param.data_count = cpu_to_be16(page_count); |
| 631 | param.data_address = cpu_to_be32((uint32_t)t_sec); | 694 | param.data_address = cpu_to_be32((uint32_t)t_sec); |
| 632 | param.cmd_param = 0; | 695 | param.tpc_param = 0; |
| 633 | 696 | ||
| 634 | msb->data_dir = rq_data_dir(req); | 697 | msb->data_dir = rq_data_dir(req); |
| 635 | msb->transfer_cmd = msb->data_dir == READ | 698 | msb->transfer_cmd = msb->data_dir == READ |
| @@ -758,10 +821,10 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) | |||
| 758 | struct memstick_host *host = card->host; | 821 | struct memstick_host *host = card->host; |
| 759 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 822 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 760 | struct mspro_param_register param = { | 823 | struct mspro_param_register param = { |
| 761 | .system = 0, | 824 | .system = MEMSTICK_SYS_PAR4, |
| 762 | .data_count = 0, | 825 | .data_count = 0, |
| 763 | .data_address = 0, | 826 | .data_address = 0, |
| 764 | .cmd_param = 0 | 827 | .tpc_param = 0 |
| 765 | }; | 828 | }; |
| 766 | 829 | ||
| 767 | card->next_request = h_mspro_block_req_init; | 830 | card->next_request = h_mspro_block_req_init; |
| @@ -773,8 +836,8 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) | |||
| 773 | if (card->current_mrq.error) | 836 | if (card->current_mrq.error) |
| 774 | return card->current_mrq.error; | 837 | return card->current_mrq.error; |
| 775 | 838 | ||
| 776 | msb->system = 0; | 839 | msb->system = MEMSTICK_SYS_PAR4; |
| 777 | host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PARALLEL); | 840 | host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); |
| 778 | 841 | ||
| 779 | card->next_request = h_mspro_block_req_init; | 842 | card->next_request = h_mspro_block_req_init; |
| 780 | msb->mrq_handler = h_mspro_block_default; | 843 | msb->mrq_handler = h_mspro_block_default; |
| @@ -783,8 +846,24 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) | |||
| 783 | wait_for_completion(&card->mrq_complete); | 846 | wait_for_completion(&card->mrq_complete); |
| 784 | 847 | ||
| 785 | if (card->current_mrq.error) { | 848 | if (card->current_mrq.error) { |
| 786 | msb->system = 0x80; | 849 | msb->system = MEMSTICK_SYS_SERIAL; |
| 850 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); | ||
| 851 | msleep(1000); | ||
| 852 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); | ||
| 787 | host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); | 853 | host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); |
| 854 | |||
| 855 | if (memstick_set_rw_addr(card)) | ||
| 856 | return card->current_mrq.error; | ||
| 857 | |||
| 858 | param.system = msb->system; | ||
| 859 | |||
| 860 | card->next_request = h_mspro_block_req_init; | ||
| 861 | msb->mrq_handler = h_mspro_block_default; | ||
| 862 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, | ||
| 863 | sizeof(param)); | ||
| 864 | memstick_new_req(host); | ||
| 865 | wait_for_completion(&card->mrq_complete); | ||
| 866 | |||
| 788 | return -EFAULT; | 867 | return -EFAULT; |
| 789 | } | 868 | } |
| 790 | 869 | ||
| @@ -802,7 +881,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card) | |||
| 802 | .system = msb->system, | 881 | .system = msb->system, |
| 803 | .data_count = cpu_to_be16(1), | 882 | .data_count = cpu_to_be16(1), |
| 804 | .data_address = 0, | 883 | .data_address = 0, |
| 805 | .cmd_param = 0 | 884 | .tpc_param = 0 |
| 806 | }; | 885 | }; |
| 807 | struct mspro_attribute *attr = NULL; | 886 | struct mspro_attribute *attr = NULL; |
| 808 | struct mspro_sys_attr *s_attr = NULL; | 887 | struct mspro_sys_attr *s_attr = NULL; |
| @@ -922,7 +1001,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card) | |||
| 922 | param.system = msb->system; | 1001 | param.system = msb->system; |
| 923 | param.data_count = cpu_to_be16((rc / msb->page_size) + 1); | 1002 | param.data_count = cpu_to_be16((rc / msb->page_size) + 1); |
| 924 | param.data_address = cpu_to_be32(addr / msb->page_size); | 1003 | param.data_address = cpu_to_be32(addr / msb->page_size); |
| 925 | param.cmd_param = 0; | 1004 | param.tpc_param = 0; |
| 926 | 1005 | ||
| 927 | sg_init_one(&msb->req_sg[0], buffer, | 1006 | sg_init_one(&msb->req_sg[0], buffer, |
| 928 | be16_to_cpu(param.data_count) * msb->page_size); | 1007 | be16_to_cpu(param.data_count) * msb->page_size); |
| @@ -964,7 +1043,7 @@ static int mspro_block_init_card(struct memstick_dev *card) | |||
| 964 | struct memstick_host *host = card->host; | 1043 | struct memstick_host *host = card->host; |
| 965 | int rc = 0; | 1044 | int rc = 0; |
| 966 | 1045 | ||
| 967 | msb->system = 0x80; | 1046 | msb->system = MEMSTICK_SYS_SERIAL; |
| 968 | card->reg_addr.r_offset = offsetof(struct mspro_register, status); | 1047 | card->reg_addr.r_offset = offsetof(struct mspro_register, status); |
| 969 | card->reg_addr.r_length = sizeof(struct ms_status_register); | 1048 | card->reg_addr.r_length = sizeof(struct ms_status_register); |
| 970 | card->reg_addr.w_offset = offsetof(struct mspro_register, param); | 1049 | card->reg_addr.w_offset = offsetof(struct mspro_register, param); |
| @@ -973,7 +1052,7 @@ static int mspro_block_init_card(struct memstick_dev *card) | |||
| 973 | if (memstick_set_rw_addr(card)) | 1052 | if (memstick_set_rw_addr(card)) |
| 974 | return -EIO; | 1053 | return -EIO; |
| 975 | 1054 | ||
| 976 | if (host->caps & MEMSTICK_CAP_PARALLEL) { | 1055 | if (host->caps & MEMSTICK_CAP_PAR4) { |
| 977 | if (mspro_block_switch_to_parallel(card)) | 1056 | if (mspro_block_switch_to_parallel(card)) |
| 978 | printk(KERN_WARNING "%s: could not switch to " | 1057 | printk(KERN_WARNING "%s: could not switch to " |
| 979 | "parallel interface\n", card->dev.bus_id); | 1058 | "parallel interface\n", card->dev.bus_id); |
| @@ -1348,4 +1427,3 @@ MODULE_LICENSE("GPL"); | |||
| 1348 | MODULE_AUTHOR("Alex Dubov"); | 1427 | MODULE_AUTHOR("Alex Dubov"); |
| 1349 | MODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); | 1428 | MODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); |
| 1350 | MODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); | 1429 | MODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); |
| 1351 | MODULE_VERSION(DRIVER_VERSION); | ||
diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index c002fcc3c879..4ce5c8dffb68 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig | |||
| @@ -20,3 +20,13 @@ config MEMSTICK_TIFM_MS | |||
| 20 | To compile this driver as a module, choose M here: the | 20 | To compile this driver as a module, choose M here: the |
| 21 | module will be called tifm_ms. | 21 | module will be called tifm_ms. |
| 22 | 22 | ||
| 23 | config MEMSTICK_JMICRON_38X | ||
| 24 | tristate "JMicron JMB38X MemoryStick interface support (EXPERIMENTAL)" | ||
| 25 | depends on EXPERIMENTAL && PCI | ||
| 26 | |||
| 27 | help | ||
| 28 | Say Y here if you want to be able to access MemoryStick cards with | ||
| 29 | the JMicron(R) JMB38X MemoryStick card reader. | ||
| 30 | |||
| 31 | To compile this driver as a module, choose M here: the | ||
| 32 | module will be called jmb38x_ms. | ||
diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index ee666380efa1..12530e4311d3 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | ifeq ($(CONFIG_MEMSTICK_DEBUG),y) | 5 | ifeq ($(CONFIG_MEMSTICK_DEBUG),y) |
| 6 | EXTRA_CFLAGS += -DDEBUG | 6 | EXTRA_CFLAGS += -DDEBUG |
| 7 | endif | 7 | endif |
| 8 | 8 | ||
| 9 | obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o | 9 | obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o |
| 10 | 10 | obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o | |
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c new file mode 100644 index 000000000000..03fe8783b1ee --- /dev/null +++ b/drivers/memstick/host/jmb38x_ms.c | |||
| @@ -0,0 +1,945 @@ | |||
| 1 | /* | ||
| 2 | * jmb38x_ms.c - JMicron jmb38x MemoryStick card reader | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Alex Dubov <oakad@yahoo.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/spinlock.h> | ||
| 13 | #include <linux/interrupt.h> | ||
| 14 | #include <linux/pci.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/highmem.h> | ||
| 17 | #include <linux/memstick.h> | ||
| 18 | |||
| 19 | #define DRIVER_NAME "jmb38x_ms" | ||
| 20 | |||
| 21 | static int no_dma; | ||
| 22 | module_param(no_dma, bool, 0644); | ||
| 23 | |||
| 24 | enum { | ||
| 25 | DMA_ADDRESS = 0x00, | ||
| 26 | BLOCK = 0x04, | ||
| 27 | DMA_CONTROL = 0x08, | ||
| 28 | TPC_P0 = 0x0c, | ||
| 29 | TPC_P1 = 0x10, | ||
| 30 | TPC = 0x14, | ||
| 31 | HOST_CONTROL = 0x18, | ||
| 32 | DATA = 0x1c, | ||
| 33 | STATUS = 0x20, | ||
| 34 | INT_STATUS = 0x24, | ||
| 35 | INT_STATUS_ENABLE = 0x28, | ||
| 36 | INT_SIGNAL_ENABLE = 0x2c, | ||
| 37 | TIMER = 0x30, | ||
| 38 | TIMER_CONTROL = 0x34, | ||
| 39 | PAD_OUTPUT_ENABLE = 0x38, | ||
| 40 | PAD_PU_PD = 0x3c, | ||
| 41 | CLOCK_DELAY = 0x40, | ||
| 42 | ADMA_ADDRESS = 0x44, | ||
| 43 | CLOCK_CONTROL = 0x48, | ||
| 44 | LED_CONTROL = 0x4c, | ||
| 45 | VERSION = 0x50 | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct jmb38x_ms_host { | ||
| 49 | struct jmb38x_ms *chip; | ||
| 50 | void __iomem *addr; | ||
| 51 | spinlock_t lock; | ||
| 52 | int id; | ||
| 53 | char host_id[DEVICE_ID_SIZE]; | ||
| 54 | int irq; | ||
| 55 | unsigned int block_pos; | ||
| 56 | unsigned long timeout_jiffies; | ||
| 57 | struct timer_list timer; | ||
| 58 | struct memstick_request *req; | ||
| 59 | unsigned char eject:1, | ||
| 60 | use_dma:1; | ||
| 61 | unsigned char cmd_flags; | ||
| 62 | unsigned char io_pos; | ||
| 63 | unsigned int io_word[2]; | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct jmb38x_ms { | ||
| 67 | struct pci_dev *pdev; | ||
| 68 | int host_cnt; | ||
| 69 | struct memstick_host *hosts[]; | ||
| 70 | }; | ||
| 71 | |||
| 72 | #define BLOCK_COUNT_MASK 0xffff0000 | ||
| 73 | #define BLOCK_SIZE_MASK 0x00000fff | ||
| 74 | |||
| 75 | #define DMA_CONTROL_ENABLE 0x00000001 | ||
| 76 | |||
| 77 | #define TPC_DATA_SEL 0x00008000 | ||
| 78 | #define TPC_DIR 0x00004000 | ||
| 79 | #define TPC_WAIT_INT 0x00002000 | ||
| 80 | #define TPC_GET_INT 0x00000800 | ||
| 81 | #define TPC_CODE_SZ_MASK 0x00000700 | ||
| 82 | #define TPC_DATA_SZ_MASK 0x00000007 | ||
| 83 | |||
| 84 | #define HOST_CONTROL_RESET_REQ 0x00008000 | ||
| 85 | #define HOST_CONTROL_REI 0x00004000 | ||
| 86 | #define HOST_CONTROL_LED 0x00000400 | ||
| 87 | #define HOST_CONTROL_FAST_CLK 0x00000200 | ||
| 88 | #define HOST_CONTROL_RESET 0x00000100 | ||
| 89 | #define HOST_CONTROL_POWER_EN 0x00000080 | ||
| 90 | #define HOST_CONTROL_CLOCK_EN 0x00000040 | ||
| 91 | #define HOST_CONTROL_IF_SHIFT 4 | ||
| 92 | |||
| 93 | #define HOST_CONTROL_IF_SERIAL 0x0 | ||
| 94 | #define HOST_CONTROL_IF_PAR4 0x1 | ||
| 95 | #define HOST_CONTROL_IF_PAR8 0x3 | ||
| 96 | |||
| 97 | #define STATUS_HAS_MEDIA 0x00000400 | ||
| 98 | #define STATUS_FIFO_EMPTY 0x00000200 | ||
| 99 | #define STATUS_FIFO_FULL 0x00000100 | ||
| 100 | |||
| 101 | #define INT_STATUS_TPC_ERR 0x00080000 | ||
| 102 | #define INT_STATUS_CRC_ERR 0x00040000 | ||
| 103 | #define INT_STATUS_TIMER_TO 0x00020000 | ||
| 104 | #define INT_STATUS_HSK_TO 0x00010000 | ||
| 105 | #define INT_STATUS_ANY_ERR 0x00008000 | ||
| 106 | #define INT_STATUS_FIFO_WRDY 0x00000080 | ||
| 107 | #define INT_STATUS_FIFO_RRDY 0x00000040 | ||
| 108 | #define INT_STATUS_MEDIA_OUT 0x00000010 | ||
| 109 | #define INT_STATUS_MEDIA_IN 0x00000008 | ||
| 110 | #define INT_STATUS_DMA_BOUNDARY 0x00000004 | ||
| 111 | #define INT_STATUS_EOTRAN 0x00000002 | ||
| 112 | #define INT_STATUS_EOTPC 0x00000001 | ||
| 113 | |||
| 114 | #define INT_STATUS_ALL 0x000f801f | ||
| 115 | |||
| 116 | #define PAD_OUTPUT_ENABLE_MS 0x0F3F | ||
| 117 | |||
| 118 | #define PAD_PU_PD_OFF 0x7FFF0000 | ||
| 119 | #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 | ||
| 120 | #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 | ||
| 121 | |||
| 122 | enum { | ||
| 123 | CMD_READY = 0x01, | ||
| 124 | FIFO_READY = 0x02, | ||
| 125 | REG_DATA = 0x04, | ||
| 126 | AUTO_GET_INT = 0x08 | ||
| 127 | }; | ||
| 128 | |||
| 129 | static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, | ||
| 130 | unsigned char *buf, unsigned int length) | ||
| 131 | { | ||
| 132 | unsigned int off = 0; | ||
| 133 | |||
| 134 | while (host->io_pos && length) { | ||
| 135 | buf[off++] = host->io_word[0] & 0xff; | ||
| 136 | host->io_word[0] >>= 8; | ||
| 137 | length--; | ||
| 138 | host->io_pos--; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (!length) | ||
| 142 | return off; | ||
| 143 | |||
| 144 | while (!(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { | ||
| 145 | if (length < 4) | ||
| 146 | break; | ||
| 147 | *(unsigned int *)(buf + off) = __raw_readl(host->addr + DATA); | ||
| 148 | length -= 4; | ||
| 149 | off += 4; | ||
| 150 | } | ||
| 151 | |||
| 152 | if (length | ||
| 153 | && !(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { | ||
| 154 | host->io_word[0] = readl(host->addr + DATA); | ||
| 155 | for (host->io_pos = 4; host->io_pos; --host->io_pos) { | ||
| 156 | buf[off++] = host->io_word[0] & 0xff; | ||
| 157 | host->io_word[0] >>= 8; | ||
| 158 | length--; | ||
| 159 | if (!length) | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | return off; | ||
| 165 | } | ||
| 166 | |||
| 167 | static unsigned int jmb38x_ms_read_reg_data(struct jmb38x_ms_host *host, | ||
| 168 | unsigned char *buf, | ||
| 169 | unsigned int length) | ||
| 170 | { | ||
| 171 | unsigned int off = 0; | ||
| 172 | |||
| 173 | while (host->io_pos > 4 && length) { | ||
| 174 | buf[off++] = host->io_word[0] & 0xff; | ||
| 175 | host->io_word[0] >>= 8; | ||
| 176 | length--; | ||
| 177 | host->io_pos--; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (!length) | ||
| 181 | return off; | ||
| 182 | |||
| 183 | while (host->io_pos && length) { | ||
| 184 | buf[off++] = host->io_word[1] & 0xff; | ||
| 185 | host->io_word[1] >>= 8; | ||
| 186 | length--; | ||
| 187 | host->io_pos--; | ||
| 188 | } | ||
| 189 | |||
| 190 | return off; | ||
| 191 | } | ||
| 192 | |||
| 193 | static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host, | ||
| 194 | unsigned char *buf, | ||
| 195 | unsigned int length) | ||
| 196 | { | ||
| 197 | unsigned int off = 0; | ||
| 198 | |||
| 199 | if (host->io_pos) { | ||
| 200 | while (host->io_pos < 4 && length) { | ||
| 201 | host->io_word[0] |= buf[off++] << (host->io_pos * 8); | ||
| 202 | host->io_pos++; | ||
| 203 | length--; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | if (host->io_pos == 4 | ||
| 208 | && !(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { | ||
| 209 | writel(host->io_word[0], host->addr + DATA); | ||
| 210 | host->io_pos = 0; | ||
| 211 | host->io_word[0] = 0; | ||
| 212 | } else if (host->io_pos) { | ||
| 213 | return off; | ||
| 214 | } | ||
| 215 | |||
| 216 | if (!length) | ||
| 217 | return off; | ||
| 218 | |||
| 219 | while (!(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { | ||
| 220 | if (length < 4) | ||
| 221 | break; | ||
| 222 | |||
| 223 | __raw_writel(*(unsigned int *)(buf + off), | ||
| 224 | host->addr + DATA); | ||
| 225 | length -= 4; | ||
| 226 | off += 4; | ||
| 227 | } | ||
| 228 | |||
| 229 | switch (length) { | ||
| 230 | case 3: | ||
| 231 | host->io_word[0] |= buf[off + 2] << 16; | ||
| 232 | host->io_pos++; | ||
| 233 | case 2: | ||
| 234 | host->io_word[0] |= buf[off + 1] << 8; | ||
| 235 | host->io_pos++; | ||
| 236 | case 1: | ||
| 237 | host->io_word[0] |= buf[off]; | ||
| 238 | host->io_pos++; | ||
| 239 | } | ||
| 240 | |||
| 241 | off += host->io_pos; | ||
| 242 | |||
| 243 | return off; | ||
| 244 | } | ||
| 245 | |||
| 246 | static unsigned int jmb38x_ms_write_reg_data(struct jmb38x_ms_host *host, | ||
| 247 | unsigned char *buf, | ||
| 248 | unsigned int length) | ||
| 249 | { | ||
| 250 | unsigned int off = 0; | ||
| 251 | |||
| 252 | while (host->io_pos < 4 && length) { | ||
| 253 | host->io_word[0] &= ~(0xff << (host->io_pos * 8)); | ||
| 254 | host->io_word[0] |= buf[off++] << (host->io_pos * 8); | ||
| 255 | host->io_pos++; | ||
| 256 | length--; | ||
| 257 | } | ||
| 258 | |||
| 259 | if (!length) | ||
| 260 | return off; | ||
| 261 | |||
| 262 | while (host->io_pos < 8 && length) { | ||
| 263 | host->io_word[1] &= ~(0xff << (host->io_pos * 8)); | ||
| 264 | host->io_word[1] |= buf[off++] << (host->io_pos * 8); | ||
| 265 | host->io_pos++; | ||
| 266 | length--; | ||
| 267 | } | ||
| 268 | |||
| 269 | return off; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) | ||
| 273 | { | ||
| 274 | unsigned int length; | ||
| 275 | unsigned int off; | ||
| 276 | unsigned int t_size, p_off, p_cnt; | ||
| 277 | unsigned char *buf; | ||
| 278 | struct page *pg; | ||
| 279 | unsigned long flags = 0; | ||
| 280 | |||
| 281 | if (host->req->long_data) { | ||
| 282 | length = host->req->sg.length - host->block_pos; | ||
| 283 | off = host->req->sg.offset + host->block_pos; | ||
| 284 | } else { | ||
| 285 | length = host->req->data_len - host->block_pos; | ||
| 286 | off = 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | while (length) { | ||
| 290 | if (host->req->long_data) { | ||
| 291 | pg = nth_page(sg_page(&host->req->sg), | ||
| 292 | off >> PAGE_SHIFT); | ||
| 293 | p_off = offset_in_page(off); | ||
| 294 | p_cnt = PAGE_SIZE - p_off; | ||
| 295 | p_cnt = min(p_cnt, length); | ||
| 296 | |||
| 297 | local_irq_save(flags); | ||
| 298 | buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; | ||
| 299 | } else { | ||
| 300 | buf = host->req->data + host->block_pos; | ||
| 301 | p_cnt = host->req->data_len - host->block_pos; | ||
| 302 | } | ||
| 303 | |||
| 304 | if (host->req->data_dir == WRITE) | ||
| 305 | t_size = !(host->cmd_flags & REG_DATA) | ||
| 306 | ? jmb38x_ms_write_data(host, buf, p_cnt) | ||
| 307 | : jmb38x_ms_write_reg_data(host, buf, p_cnt); | ||
| 308 | else | ||
| 309 | t_size = !(host->cmd_flags & REG_DATA) | ||
| 310 | ? jmb38x_ms_read_data(host, buf, p_cnt) | ||
| 311 | : jmb38x_ms_read_reg_data(host, buf, p_cnt); | ||
| 312 | |||
| 313 | if (host->req->long_data) { | ||
| 314 | kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); | ||
| 315 | local_irq_restore(flags); | ||
| 316 | } | ||
| 317 | |||
| 318 | if (!t_size) | ||
| 319 | break; | ||
| 320 | host->block_pos += t_size; | ||
| 321 | length -= t_size; | ||
| 322 | off += t_size; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (!length && host->req->data_dir == WRITE) { | ||
| 326 | if (host->cmd_flags & REG_DATA) { | ||
| 327 | writel(host->io_word[0], host->addr + TPC_P0); | ||
| 328 | writel(host->io_word[1], host->addr + TPC_P1); | ||
| 329 | } else if (host->io_pos) { | ||
| 330 | writel(host->io_word[0], host->addr + DATA); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | return length; | ||
| 335 | } | ||
| 336 | |||
| 337 | static int jmb38x_ms_issue_cmd(struct memstick_host *msh) | ||
| 338 | { | ||
| 339 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 340 | unsigned char *data; | ||
| 341 | unsigned int data_len, cmd, t_val; | ||
| 342 | |||
| 343 | if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) { | ||
| 344 | dev_dbg(msh->cdev.dev, "no media status\n"); | ||
| 345 | host->req->error = -ETIME; | ||
| 346 | return host->req->error; | ||
| 347 | } | ||
| 348 | |||
| 349 | dev_dbg(msh->cdev.dev, "control %08x\n", | ||
| 350 | readl(host->addr + HOST_CONTROL)); | ||
| 351 | dev_dbg(msh->cdev.dev, "status %08x\n", readl(host->addr + INT_STATUS)); | ||
| 352 | dev_dbg(msh->cdev.dev, "hstatus %08x\n", readl(host->addr + STATUS)); | ||
| 353 | |||
| 354 | host->cmd_flags = 0; | ||
| 355 | host->block_pos = 0; | ||
| 356 | host->io_pos = 0; | ||
| 357 | host->io_word[0] = 0; | ||
| 358 | host->io_word[1] = 0; | ||
| 359 | |||
| 360 | cmd = host->req->tpc << 16; | ||
| 361 | cmd |= TPC_DATA_SEL; | ||
| 362 | |||
| 363 | if (host->req->data_dir == READ) | ||
| 364 | cmd |= TPC_DIR; | ||
| 365 | if (host->req->need_card_int) | ||
| 366 | cmd |= TPC_WAIT_INT; | ||
| 367 | if (host->req->get_int_reg) | ||
| 368 | cmd |= TPC_GET_INT; | ||
| 369 | |||
| 370 | data = host->req->data; | ||
| 371 | |||
| 372 | host->use_dma = !no_dma; | ||
| 373 | |||
| 374 | if (host->req->long_data) { | ||
| 375 | data_len = host->req->sg.length; | ||
| 376 | } else { | ||
| 377 | data_len = host->req->data_len; | ||
| 378 | host->use_dma = 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | if (data_len <= 8) { | ||
| 382 | cmd &= ~(TPC_DATA_SEL | 0xf); | ||
| 383 | host->cmd_flags |= REG_DATA; | ||
| 384 | cmd |= data_len & 0xf; | ||
| 385 | host->use_dma = 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | if (host->use_dma) { | ||
| 389 | if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1, | ||
| 390 | host->req->data_dir == READ | ||
| 391 | ? PCI_DMA_FROMDEVICE | ||
| 392 | : PCI_DMA_TODEVICE)) { | ||
| 393 | host->req->error = -ENOMEM; | ||
| 394 | return host->req->error; | ||
| 395 | } | ||
| 396 | data_len = sg_dma_len(&host->req->sg); | ||
| 397 | writel(sg_dma_address(&host->req->sg), | ||
| 398 | host->addr + DMA_ADDRESS); | ||
| 399 | writel(((1 << 16) & BLOCK_COUNT_MASK) | ||
| 400 | | (data_len & BLOCK_SIZE_MASK), | ||
| 401 | host->addr + BLOCK); | ||
| 402 | writel(DMA_CONTROL_ENABLE, host->addr + DMA_CONTROL); | ||
| 403 | } else if (!(host->cmd_flags & REG_DATA)) { | ||
| 404 | writel(((1 << 16) & BLOCK_COUNT_MASK) | ||
| 405 | | (data_len & BLOCK_SIZE_MASK), | ||
| 406 | host->addr + BLOCK); | ||
| 407 | t_val = readl(host->addr + INT_STATUS_ENABLE); | ||
| 408 | t_val |= host->req->data_dir == READ | ||
| 409 | ? INT_STATUS_FIFO_RRDY | ||
| 410 | : INT_STATUS_FIFO_WRDY; | ||
| 411 | |||
| 412 | writel(t_val, host->addr + INT_STATUS_ENABLE); | ||
| 413 | writel(t_val, host->addr + INT_SIGNAL_ENABLE); | ||
| 414 | } else { | ||
| 415 | cmd &= ~(TPC_DATA_SEL | 0xf); | ||
| 416 | host->cmd_flags |= REG_DATA; | ||
| 417 | cmd |= data_len & 0xf; | ||
| 418 | |||
| 419 | if (host->req->data_dir == WRITE) { | ||
| 420 | jmb38x_ms_transfer_data(host); | ||
| 421 | writel(host->io_word[0], host->addr + TPC_P0); | ||
| 422 | writel(host->io_word[1], host->addr + TPC_P1); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | mod_timer(&host->timer, jiffies + host->timeout_jiffies); | ||
| 427 | writel(HOST_CONTROL_LED | readl(host->addr + HOST_CONTROL), | ||
| 428 | host->addr + HOST_CONTROL); | ||
| 429 | host->req->error = 0; | ||
| 430 | |||
| 431 | writel(cmd, host->addr + TPC); | ||
| 432 | dev_dbg(msh->cdev.dev, "executing TPC %08x, len %x\n", cmd, data_len); | ||
| 433 | |||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last) | ||
| 438 | { | ||
| 439 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 440 | unsigned int t_val = 0; | ||
| 441 | int rc; | ||
| 442 | |||
| 443 | del_timer(&host->timer); | ||
| 444 | |||
| 445 | dev_dbg(msh->cdev.dev, "c control %08x\n", | ||
| 446 | readl(host->addr + HOST_CONTROL)); | ||
| 447 | dev_dbg(msh->cdev.dev, "c status %08x\n", | ||
| 448 | readl(host->addr + INT_STATUS)); | ||
| 449 | dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); | ||
| 450 | |||
| 451 | if (host->req->get_int_reg) { | ||
| 452 | t_val = readl(host->addr + TPC_P0); | ||
| 453 | host->req->int_reg = (t_val & 0xff); | ||
| 454 | } | ||
| 455 | |||
| 456 | if (host->use_dma) { | ||
| 457 | writel(0, host->addr + DMA_CONTROL); | ||
| 458 | pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, | ||
| 459 | host->req->data_dir == READ | ||
| 460 | ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); | ||
| 461 | } else { | ||
| 462 | t_val = readl(host->addr + INT_STATUS_ENABLE); | ||
| 463 | if (host->req->data_dir == READ) | ||
| 464 | t_val &= ~INT_STATUS_FIFO_RRDY; | ||
| 465 | else | ||
| 466 | t_val &= ~INT_STATUS_FIFO_WRDY; | ||
| 467 | |||
| 468 | writel(t_val, host->addr + INT_STATUS_ENABLE); | ||
| 469 | writel(t_val, host->addr + INT_SIGNAL_ENABLE); | ||
| 470 | } | ||
| 471 | |||
| 472 | writel((~HOST_CONTROL_LED) & readl(host->addr + HOST_CONTROL), | ||
| 473 | host->addr + HOST_CONTROL); | ||
| 474 | |||
| 475 | if (!last) { | ||
| 476 | do { | ||
| 477 | rc = memstick_next_req(msh, &host->req); | ||
| 478 | } while (!rc && jmb38x_ms_issue_cmd(msh)); | ||
| 479 | } else { | ||
| 480 | do { | ||
| 481 | rc = memstick_next_req(msh, &host->req); | ||
| 482 | if (!rc) | ||
| 483 | host->req->error = -ETIME; | ||
| 484 | } while (!rc); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) | ||
| 489 | { | ||
| 490 | struct memstick_host *msh = dev_id; | ||
| 491 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 492 | unsigned int irq_status; | ||
| 493 | |||
| 494 | spin_lock(&host->lock); | ||
| 495 | irq_status = readl(host->addr + INT_STATUS); | ||
| 496 | dev_dbg(&host->chip->pdev->dev, "irq_status = %08x\n", irq_status); | ||
| 497 | if (irq_status == 0 || irq_status == (~0)) { | ||
| 498 | spin_unlock(&host->lock); | ||
| 499 | return IRQ_NONE; | ||
| 500 | } | ||
| 501 | |||
| 502 | if (host->req) { | ||
| 503 | if (irq_status & INT_STATUS_ANY_ERR) { | ||
| 504 | if (irq_status & INT_STATUS_CRC_ERR) | ||
| 505 | host->req->error = -EILSEQ; | ||
| 506 | else | ||
| 507 | host->req->error = -ETIME; | ||
| 508 | } else { | ||
| 509 | if (host->use_dma) { | ||
| 510 | if (irq_status & INT_STATUS_EOTRAN) | ||
| 511 | host->cmd_flags |= FIFO_READY; | ||
| 512 | } else { | ||
| 513 | if (irq_status & (INT_STATUS_FIFO_RRDY | ||
| 514 | | INT_STATUS_FIFO_WRDY)) | ||
| 515 | jmb38x_ms_transfer_data(host); | ||
| 516 | |||
| 517 | if (irq_status & INT_STATUS_EOTRAN) { | ||
| 518 | jmb38x_ms_transfer_data(host); | ||
| 519 | host->cmd_flags |= FIFO_READY; | ||
| 520 | } | ||
| 521 | } | ||
| 522 | |||
| 523 | if (irq_status & INT_STATUS_EOTPC) { | ||
| 524 | host->cmd_flags |= CMD_READY; | ||
| 525 | if (host->cmd_flags & REG_DATA) { | ||
| 526 | if (host->req->data_dir == READ) { | ||
| 527 | host->io_word[0] | ||
| 528 | = readl(host->addr | ||
| 529 | + TPC_P0); | ||
| 530 | host->io_word[1] | ||
| 531 | = readl(host->addr | ||
| 532 | + TPC_P1); | ||
| 533 | host->io_pos = 8; | ||
| 534 | |||
| 535 | jmb38x_ms_transfer_data(host); | ||
| 536 | } | ||
| 537 | host->cmd_flags |= FIFO_READY; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) { | ||
| 544 | dev_dbg(&host->chip->pdev->dev, "media changed\n"); | ||
| 545 | memstick_detect_change(msh); | ||
| 546 | } | ||
| 547 | |||
| 548 | writel(irq_status, host->addr + INT_STATUS); | ||
| 549 | |||
| 550 | if (host->req | ||
| 551 | && (((host->cmd_flags & CMD_READY) | ||
| 552 | && (host->cmd_flags & FIFO_READY)) | ||
| 553 | || host->req->error)) | ||
| 554 | jmb38x_ms_complete_cmd(msh, 0); | ||
| 555 | |||
| 556 | spin_unlock(&host->lock); | ||
| 557 | return IRQ_HANDLED; | ||
| 558 | } | ||
| 559 | |||
| 560 | static void jmb38x_ms_abort(unsigned long data) | ||
| 561 | { | ||
| 562 | struct memstick_host *msh = (struct memstick_host *)data; | ||
| 563 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 564 | unsigned long flags; | ||
| 565 | |||
| 566 | dev_dbg(&host->chip->pdev->dev, "abort\n"); | ||
| 567 | spin_lock_irqsave(&host->lock, flags); | ||
| 568 | if (host->req) { | ||
| 569 | host->req->error = -ETIME; | ||
| 570 | jmb38x_ms_complete_cmd(msh, 0); | ||
| 571 | } | ||
| 572 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 573 | } | ||
| 574 | |||
| 575 | static void jmb38x_ms_request(struct memstick_host *msh) | ||
| 576 | { | ||
| 577 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 578 | unsigned long flags; | ||
| 579 | int rc; | ||
| 580 | |||
| 581 | spin_lock_irqsave(&host->lock, flags); | ||
| 582 | if (host->req) { | ||
| 583 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 584 | BUG(); | ||
| 585 | return; | ||
| 586 | } | ||
| 587 | |||
| 588 | do { | ||
| 589 | rc = memstick_next_req(msh, &host->req); | ||
| 590 | } while (!rc && jmb38x_ms_issue_cmd(msh)); | ||
| 591 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 592 | } | ||
| 593 | |||
| 594 | static void jmb38x_ms_reset(struct jmb38x_ms_host *host) | ||
| 595 | { | ||
| 596 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | ||
| 597 | |||
| 598 | writel(host_ctl | HOST_CONTROL_RESET_REQ | HOST_CONTROL_RESET, | ||
| 599 | host->addr + HOST_CONTROL); | ||
| 600 | |||
| 601 | while (HOST_CONTROL_RESET_REQ | ||
| 602 | & (host_ctl = readl(host->addr + HOST_CONTROL))) { | ||
| 603 | ndelay(100); | ||
| 604 | dev_dbg(&host->chip->pdev->dev, "reset\n"); | ||
| 605 | } | ||
| 606 | |||
| 607 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); | ||
| 608 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); | ||
| 609 | |||
| 610 | dev_dbg(&host->chip->pdev->dev, "reset\n"); | ||
| 611 | } | ||
| 612 | |||
| 613 | static void jmb38x_ms_set_param(struct memstick_host *msh, | ||
| 614 | enum memstick_param param, | ||
| 615 | int value) | ||
| 616 | { | ||
| 617 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 618 | unsigned int host_ctl; | ||
| 619 | unsigned long flags; | ||
| 620 | |||
| 621 | spin_lock_irqsave(&host->lock, flags); | ||
| 622 | |||
| 623 | switch (param) { | ||
| 624 | case MEMSTICK_POWER: | ||
| 625 | if (value == MEMSTICK_POWER_ON) { | ||
| 626 | jmb38x_ms_reset(host); | ||
| 627 | |||
| 628 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 | ||
| 629 | : PAD_PU_PD_ON_MS_SOCK0, | ||
| 630 | host->addr + PAD_PU_PD); | ||
| 631 | |||
| 632 | writel(PAD_OUTPUT_ENABLE_MS, | ||
| 633 | host->addr + PAD_OUTPUT_ENABLE); | ||
| 634 | |||
| 635 | host_ctl = readl(host->addr + HOST_CONTROL); | ||
| 636 | host_ctl |= 7; | ||
| 637 | writel(host_ctl | (HOST_CONTROL_POWER_EN | ||
| 638 | | HOST_CONTROL_CLOCK_EN), | ||
| 639 | host->addr + HOST_CONTROL); | ||
| 640 | |||
| 641 | dev_dbg(&host->chip->pdev->dev, "power on\n"); | ||
| 642 | } else if (value == MEMSTICK_POWER_OFF) { | ||
| 643 | writel(readl(host->addr + HOST_CONTROL) | ||
| 644 | & ~(HOST_CONTROL_POWER_EN | ||
| 645 | | HOST_CONTROL_CLOCK_EN), | ||
| 646 | host->addr + HOST_CONTROL); | ||
| 647 | writel(0, host->addr + PAD_OUTPUT_ENABLE); | ||
| 648 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); | ||
| 649 | dev_dbg(&host->chip->pdev->dev, "power off\n"); | ||
| 650 | } | ||
| 651 | break; | ||
| 652 | case MEMSTICK_INTERFACE: | ||
| 653 | /* jmb38x_ms_reset(host); */ | ||
| 654 | |||
| 655 | host_ctl = readl(host->addr + HOST_CONTROL); | ||
| 656 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); | ||
| 657 | /* host_ctl |= 7; */ | ||
| 658 | |||
| 659 | if (value == MEMSTICK_SERIAL) { | ||
| 660 | host_ctl &= ~HOST_CONTROL_FAST_CLK; | ||
| 661 | host_ctl |= HOST_CONTROL_IF_SERIAL | ||
| 662 | << HOST_CONTROL_IF_SHIFT; | ||
| 663 | host_ctl |= HOST_CONTROL_REI; | ||
| 664 | writel(0, host->addr + CLOCK_DELAY); | ||
| 665 | } else if (value == MEMSTICK_PAR4) { | ||
| 666 | host_ctl |= HOST_CONTROL_FAST_CLK; | ||
| 667 | host_ctl |= HOST_CONTROL_IF_PAR4 | ||
| 668 | << HOST_CONTROL_IF_SHIFT; | ||
| 669 | host_ctl &= ~HOST_CONTROL_REI; | ||
| 670 | writel(4, host->addr + CLOCK_DELAY); | ||
| 671 | } else if (value == MEMSTICK_PAR8) { | ||
| 672 | host_ctl |= HOST_CONTROL_FAST_CLK; | ||
| 673 | host_ctl |= HOST_CONTROL_IF_PAR8 | ||
| 674 | << HOST_CONTROL_IF_SHIFT; | ||
| 675 | host_ctl &= ~HOST_CONTROL_REI; | ||
| 676 | writel(4, host->addr + CLOCK_DELAY); | ||
| 677 | } | ||
| 678 | writel(host_ctl, host->addr + HOST_CONTROL); | ||
| 679 | break; | ||
| 680 | }; | ||
| 681 | |||
| 682 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 683 | } | ||
| 684 | |||
| 685 | #ifdef CONFIG_PM | ||
| 686 | |||
| 687 | static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) | ||
| 688 | { | ||
| 689 | struct jmb38x_ms *jm = pci_get_drvdata(dev); | ||
| 690 | int cnt; | ||
| 691 | |||
| 692 | for (cnt = 0; cnt < jm->host_cnt; ++cnt) { | ||
| 693 | if (!jm->hosts[cnt]) | ||
| 694 | break; | ||
| 695 | memstick_suspend_host(jm->hosts[cnt]); | ||
| 696 | } | ||
| 697 | |||
| 698 | pci_save_state(dev); | ||
| 699 | pci_enable_wake(dev, pci_choose_state(dev, state), 0); | ||
| 700 | pci_disable_device(dev); | ||
| 701 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
| 702 | return 0; | ||
| 703 | } | ||
| 704 | |||
| 705 | static int jmb38x_ms_resume(struct pci_dev *dev) | ||
| 706 | { | ||
| 707 | struct jmb38x_ms *jm = pci_get_drvdata(dev); | ||
| 708 | int rc; | ||
| 709 | |||
| 710 | pci_set_power_state(dev, PCI_D0); | ||
| 711 | pci_restore_state(dev); | ||
| 712 | rc = pci_enable_device(dev); | ||
| 713 | if (rc) | ||
| 714 | return rc; | ||
| 715 | pci_set_master(dev); | ||
| 716 | |||
| 717 | pci_read_config_dword(dev, 0xac, &rc); | ||
| 718 | pci_write_config_dword(dev, 0xac, rc | 0x00470000); | ||
| 719 | |||
| 720 | for (rc = 0; rc < jm->host_cnt; ++rc) { | ||
| 721 | if (!jm->hosts[rc]) | ||
| 722 | break; | ||
| 723 | memstick_resume_host(jm->hosts[rc]); | ||
| 724 | memstick_detect_change(jm->hosts[rc]); | ||
| 725 | } | ||
| 726 | |||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | #else | ||
| 731 | |||
| 732 | #define jmb38x_ms_suspend NULL | ||
| 733 | #define jmb38x_ms_resume NULL | ||
| 734 | |||
| 735 | #endif /* CONFIG_PM */ | ||
| 736 | |||
| 737 | static int jmb38x_ms_count_slots(struct pci_dev *pdev) | ||
| 738 | { | ||
| 739 | int cnt, rc = 0; | ||
| 740 | |||
| 741 | for (cnt = 0; cnt < PCI_ROM_RESOURCE; ++cnt) { | ||
| 742 | if (!(IORESOURCE_MEM & pci_resource_flags(pdev, cnt))) | ||
| 743 | break; | ||
| 744 | |||
| 745 | if (256 != pci_resource_len(pdev, cnt)) | ||
| 746 | break; | ||
| 747 | |||
| 748 | ++rc; | ||
| 749 | } | ||
| 750 | return rc; | ||
| 751 | } | ||
| 752 | |||
| 753 | static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) | ||
| 754 | { | ||
| 755 | struct memstick_host *msh; | ||
| 756 | struct jmb38x_ms_host *host; | ||
| 757 | |||
| 758 | msh = memstick_alloc_host(sizeof(struct jmb38x_ms_host), | ||
| 759 | &jm->pdev->dev); | ||
| 760 | if (!msh) | ||
| 761 | return NULL; | ||
| 762 | |||
| 763 | host = memstick_priv(msh); | ||
| 764 | host->chip = jm; | ||
| 765 | host->addr = ioremap(pci_resource_start(jm->pdev, cnt), | ||
| 766 | pci_resource_len(jm->pdev, cnt)); | ||
| 767 | if (!host->addr) | ||
| 768 | goto err_out_free; | ||
| 769 | |||
| 770 | spin_lock_init(&host->lock); | ||
| 771 | host->id = cnt; | ||
| 772 | snprintf(host->host_id, DEVICE_ID_SIZE, DRIVER_NAME ":slot%d", | ||
| 773 | host->id); | ||
| 774 | host->irq = jm->pdev->irq; | ||
| 775 | host->timeout_jiffies = msecs_to_jiffies(4000); | ||
| 776 | msh->request = jmb38x_ms_request; | ||
| 777 | msh->set_param = jmb38x_ms_set_param; | ||
| 778 | /* | ||
| 779 | msh->caps = MEMSTICK_CAP_AUTO_GET_INT | MEMSTICK_CAP_PAR4 | ||
| 780 | | MEMSTICK_CAP_PAR8; | ||
| 781 | */ | ||
| 782 | msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; | ||
| 783 | |||
| 784 | setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh); | ||
| 785 | |||
| 786 | if (!request_irq(host->irq, jmb38x_ms_isr, IRQF_SHARED, host->host_id, | ||
| 787 | msh)) | ||
| 788 | return msh; | ||
| 789 | |||
| 790 | iounmap(host->addr); | ||
| 791 | err_out_free: | ||
| 792 | kfree(msh); | ||
| 793 | return NULL; | ||
| 794 | } | ||
| 795 | |||
| 796 | static void jmb38x_ms_free_host(struct memstick_host *msh) | ||
| 797 | { | ||
| 798 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 799 | |||
| 800 | free_irq(host->irq, msh); | ||
| 801 | iounmap(host->addr); | ||
| 802 | memstick_free_host(msh); | ||
| 803 | } | ||
| 804 | |||
| 805 | static int jmb38x_ms_probe(struct pci_dev *pdev, | ||
| 806 | const struct pci_device_id *dev_id) | ||
| 807 | { | ||
| 808 | struct jmb38x_ms *jm; | ||
| 809 | int pci_dev_busy = 0; | ||
| 810 | int rc, cnt; | ||
| 811 | |||
| 812 | rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
| 813 | if (rc) | ||
| 814 | return rc; | ||
| 815 | |||
| 816 | rc = pci_enable_device(pdev); | ||
| 817 | if (rc) | ||
| 818 | return rc; | ||
| 819 | |||
| 820 | pci_set_master(pdev); | ||
| 821 | |||
| 822 | rc = pci_request_regions(pdev, DRIVER_NAME); | ||
| 823 | if (rc) { | ||
| 824 | pci_dev_busy = 1; | ||
| 825 | goto err_out; | ||
| 826 | } | ||
| 827 | |||
| 828 | pci_read_config_dword(pdev, 0xac, &rc); | ||
| 829 | pci_write_config_dword(pdev, 0xac, rc | 0x00470000); | ||
| 830 | |||
| 831 | cnt = jmb38x_ms_count_slots(pdev); | ||
| 832 | if (!cnt) { | ||
| 833 | rc = -ENODEV; | ||
| 834 | pci_dev_busy = 1; | ||
| 835 | goto err_out; | ||
| 836 | } | ||
| 837 | |||
| 838 | jm = kzalloc(sizeof(struct jmb38x_ms) | ||
| 839 | + cnt * sizeof(struct memstick_host *), GFP_KERNEL); | ||
| 840 | if (!jm) { | ||
| 841 | rc = -ENOMEM; | ||
| 842 | goto err_out_int; | ||
| 843 | } | ||
| 844 | |||
| 845 | jm->pdev = pdev; | ||
| 846 | jm->host_cnt = cnt; | ||
| 847 | pci_set_drvdata(pdev, jm); | ||
| 848 | |||
| 849 | for (cnt = 0; cnt < jm->host_cnt; ++cnt) { | ||
| 850 | jm->hosts[cnt] = jmb38x_ms_alloc_host(jm, cnt); | ||
| 851 | if (!jm->hosts[cnt]) | ||
| 852 | break; | ||
| 853 | |||
| 854 | rc = memstick_add_host(jm->hosts[cnt]); | ||
| 855 | |||
| 856 | if (rc) { | ||
| 857 | jmb38x_ms_free_host(jm->hosts[cnt]); | ||
| 858 | jm->hosts[cnt] = NULL; | ||
| 859 | break; | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 863 | if (cnt) | ||
| 864 | return 0; | ||
| 865 | |||
| 866 | rc = -ENODEV; | ||
| 867 | |||
| 868 | pci_set_drvdata(pdev, NULL); | ||
| 869 | kfree(jm); | ||
| 870 | err_out_int: | ||
| 871 | pci_release_regions(pdev); | ||
| 872 | err_out: | ||
| 873 | if (!pci_dev_busy) | ||
| 874 | pci_disable_device(pdev); | ||
| 875 | return rc; | ||
| 876 | } | ||
| 877 | |||
| 878 | static void jmb38x_ms_remove(struct pci_dev *dev) | ||
| 879 | { | ||
| 880 | struct jmb38x_ms *jm = pci_get_drvdata(dev); | ||
| 881 | struct jmb38x_ms_host *host; | ||
| 882 | int cnt; | ||
| 883 | unsigned long flags; | ||
| 884 | |||
| 885 | for (cnt = 0; cnt < jm->host_cnt; ++cnt) { | ||
| 886 | if (!jm->hosts[cnt]) | ||
| 887 | break; | ||
| 888 | |||
| 889 | host = memstick_priv(jm->hosts[cnt]); | ||
| 890 | |||
| 891 | writel(0, host->addr + INT_SIGNAL_ENABLE); | ||
| 892 | writel(0, host->addr + INT_STATUS_ENABLE); | ||
| 893 | mmiowb(); | ||
| 894 | dev_dbg(&jm->pdev->dev, "interrupts off\n"); | ||
| 895 | spin_lock_irqsave(&host->lock, flags); | ||
| 896 | if (host->req) { | ||
| 897 | host->req->error = -ETIME; | ||
| 898 | jmb38x_ms_complete_cmd(jm->hosts[cnt], 1); | ||
| 899 | } | ||
| 900 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 901 | |||
| 902 | memstick_remove_host(jm->hosts[cnt]); | ||
| 903 | dev_dbg(&jm->pdev->dev, "host removed\n"); | ||
| 904 | |||
| 905 | jmb38x_ms_free_host(jm->hosts[cnt]); | ||
| 906 | } | ||
| 907 | |||
| 908 | pci_set_drvdata(dev, NULL); | ||
| 909 | pci_release_regions(dev); | ||
| 910 | pci_disable_device(dev); | ||
| 911 | kfree(jm); | ||
| 912 | } | ||
| 913 | |||
| 914 | static struct pci_device_id jmb38x_ms_id_tbl [] = { | ||
| 915 | { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, | ||
| 916 | PCI_ANY_ID, 0, 0, 0 }, | ||
| 917 | { } | ||
| 918 | }; | ||
| 919 | |||
| 920 | static struct pci_driver jmb38x_ms_driver = { | ||
| 921 | .name = DRIVER_NAME, | ||
| 922 | .id_table = jmb38x_ms_id_tbl, | ||
| 923 | .probe = jmb38x_ms_probe, | ||
| 924 | .remove = jmb38x_ms_remove, | ||
| 925 | .suspend = jmb38x_ms_suspend, | ||
| 926 | .resume = jmb38x_ms_resume | ||
| 927 | }; | ||
| 928 | |||
| 929 | static int __init jmb38x_ms_init(void) | ||
| 930 | { | ||
| 931 | return pci_register_driver(&jmb38x_ms_driver); | ||
| 932 | } | ||
| 933 | |||
| 934 | static void __exit jmb38x_ms_exit(void) | ||
| 935 | { | ||
| 936 | pci_unregister_driver(&jmb38x_ms_driver); | ||
| 937 | } | ||
| 938 | |||
| 939 | MODULE_AUTHOR("Alex Dubov"); | ||
| 940 | MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver"); | ||
| 941 | MODULE_LICENSE("GPL"); | ||
| 942 | MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl); | ||
| 943 | |||
| 944 | module_init(jmb38x_ms_init); | ||
| 945 | module_exit(jmb38x_ms_exit); | ||
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 4fb24215bd95..2b5bf52a8302 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c | |||
| @@ -20,293 +20,315 @@ | |||
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | 21 | ||
| 22 | #define DRIVER_NAME "tifm_ms" | 22 | #define DRIVER_NAME "tifm_ms" |
| 23 | #define DRIVER_VERSION "0.1" | ||
| 24 | 23 | ||
| 25 | static int no_dma; | 24 | static int no_dma; |
| 26 | module_param(no_dma, bool, 0644); | 25 | module_param(no_dma, bool, 0644); |
| 27 | 26 | ||
| 28 | #define TIFM_MS_TIMEOUT 0x00100 | 27 | /* |
| 29 | #define TIFM_MS_BADCRC 0x00200 | 28 | * Some control bits of TIFM appear to conform to Sony's reference design, |
| 30 | #define TIFM_MS_EOTPC 0x01000 | 29 | * so I'm just assuming they all are. |
| 31 | #define TIFM_MS_INT 0x02000 | 30 | */ |
| 32 | |||
| 33 | /* The meaning of the bit majority in this constant is unknown. */ | ||
| 34 | #define TIFM_MS_SERIAL 0x04010 | ||
| 35 | 31 | ||
| 36 | #define TIFM_MS_SYS_LATCH 0x00100 | 32 | #define TIFM_MS_STAT_DRQ 0x04000 |
| 37 | #define TIFM_MS_SYS_NOT_RDY 0x00800 | 33 | #define TIFM_MS_STAT_MSINT 0x02000 |
| 38 | #define TIFM_MS_SYS_DATA 0x10000 | 34 | #define TIFM_MS_STAT_RDY 0x01000 |
| 35 | #define TIFM_MS_STAT_CRC 0x00200 | ||
| 36 | #define TIFM_MS_STAT_TOE 0x00100 | ||
| 37 | #define TIFM_MS_STAT_EMP 0x00020 | ||
| 38 | #define TIFM_MS_STAT_FUL 0x00010 | ||
| 39 | #define TIFM_MS_STAT_CED 0x00008 | ||
| 40 | #define TIFM_MS_STAT_ERR 0x00004 | ||
| 41 | #define TIFM_MS_STAT_BRQ 0x00002 | ||
| 42 | #define TIFM_MS_STAT_CNK 0x00001 | ||
| 43 | |||
| 44 | #define TIFM_MS_SYS_DMA 0x10000 | ||
| 45 | #define TIFM_MS_SYS_RESET 0x08000 | ||
| 46 | #define TIFM_MS_SYS_SRAC 0x04000 | ||
| 47 | #define TIFM_MS_SYS_INTEN 0x02000 | ||
| 48 | #define TIFM_MS_SYS_NOCRC 0x01000 | ||
| 49 | #define TIFM_MS_SYS_INTCLR 0x00800 | ||
| 50 | #define TIFM_MS_SYS_MSIEN 0x00400 | ||
| 51 | #define TIFM_MS_SYS_FCLR 0x00200 | ||
| 52 | #define TIFM_MS_SYS_FDIR 0x00100 | ||
| 53 | #define TIFM_MS_SYS_DAM 0x00080 | ||
| 54 | #define TIFM_MS_SYS_DRM 0x00040 | ||
| 55 | #define TIFM_MS_SYS_DRQSL 0x00020 | ||
| 56 | #define TIFM_MS_SYS_REI 0x00010 | ||
| 57 | #define TIFM_MS_SYS_REO 0x00008 | ||
| 58 | #define TIFM_MS_SYS_BSY_MASK 0x00007 | ||
| 59 | |||
| 60 | #define TIFM_MS_SYS_FIFO (TIFM_MS_SYS_INTEN | TIFM_MS_SYS_MSIEN \ | ||
| 61 | | TIFM_MS_SYS_FCLR | TIFM_MS_SYS_BSY_MASK) | ||
| 39 | 62 | ||
| 40 | /* Hardware flags */ | 63 | /* Hardware flags */ |
| 41 | enum { | 64 | enum { |
| 42 | CMD_READY = 0x0001, | 65 | CMD_READY = 0x01, |
| 43 | FIFO_READY = 0x0002, | 66 | FIFO_READY = 0x02, |
| 44 | CARD_READY = 0x0004, | 67 | CARD_INT = 0x04 |
| 45 | DATA_CARRY = 0x0008 | ||
| 46 | }; | 68 | }; |
| 47 | 69 | ||
| 48 | struct tifm_ms { | 70 | struct tifm_ms { |
| 49 | struct tifm_dev *dev; | 71 | struct tifm_dev *dev; |
| 50 | unsigned short eject:1, | 72 | struct timer_list timer; |
| 51 | no_dma:1; | 73 | struct memstick_request *req; |
| 52 | unsigned short cmd_flags; | ||
| 53 | unsigned int mode_mask; | 74 | unsigned int mode_mask; |
| 54 | unsigned int block_pos; | 75 | unsigned int block_pos; |
| 55 | unsigned long timeout_jiffies; | 76 | unsigned long timeout_jiffies; |
| 56 | 77 | unsigned char eject:1, | |
| 57 | struct timer_list timer; | 78 | use_dma:1; |
| 58 | struct memstick_request *req; | 79 | unsigned char cmd_flags; |
| 80 | unsigned char io_pos; | ||
| 59 | unsigned int io_word; | 81 | unsigned int io_word; |
| 60 | }; | 82 | }; |
| 61 | 83 | ||
| 62 | static void tifm_ms_read_fifo(struct tifm_ms *host, unsigned int fifo_offset, | 84 | static unsigned int tifm_ms_read_data(struct tifm_ms *host, |
| 63 | struct page *pg, unsigned int page_off, | 85 | unsigned char *buf, unsigned int length) |
| 64 | unsigned int length) | ||
| 65 | { | 86 | { |
| 66 | struct tifm_dev *sock = host->dev; | 87 | struct tifm_dev *sock = host->dev; |
| 67 | unsigned int cnt = 0, off = 0; | 88 | unsigned int off = 0; |
| 68 | unsigned char *buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + page_off; | 89 | |
| 90 | while (host->io_pos && length) { | ||
| 91 | buf[off++] = host->io_word & 0xff; | ||
| 92 | host->io_word >>= 8; | ||
| 93 | length--; | ||
| 94 | host->io_pos--; | ||
| 95 | } | ||
| 69 | 96 | ||
| 70 | if (host->cmd_flags & DATA_CARRY) { | 97 | if (!length) |
| 71 | while ((fifo_offset & 3) && length) { | 98 | return off; |
| 99 | |||
| 100 | while (!(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) { | ||
| 101 | if (length < 4) | ||
| 102 | break; | ||
| 103 | *(unsigned int *)(buf + off) = __raw_readl(sock->addr | ||
| 104 | + SOCK_MS_DATA); | ||
| 105 | length -= 4; | ||
| 106 | off += 4; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (length | ||
| 110 | && !(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) { | ||
| 111 | host->io_word = readl(sock->addr + SOCK_MS_DATA); | ||
| 112 | for (host->io_pos = 4; host->io_pos; --host->io_pos) { | ||
| 72 | buf[off++] = host->io_word & 0xff; | 113 | buf[off++] = host->io_word & 0xff; |
| 73 | host->io_word >>= 8; | 114 | host->io_word >>= 8; |
| 74 | length--; | 115 | length--; |
| 75 | fifo_offset++; | 116 | if (!length) |
| 117 | break; | ||
| 76 | } | 118 | } |
| 77 | if (!(fifo_offset & 3)) | ||
| 78 | host->cmd_flags &= ~DATA_CARRY; | ||
| 79 | if (!length) | ||
| 80 | return; | ||
| 81 | } | 119 | } |
| 82 | 120 | ||
| 83 | do { | 121 | return off; |
| 84 | host->io_word = readl(sock->addr + SOCK_FIFO_ACCESS | ||
| 85 | + fifo_offset); | ||
| 86 | cnt = 4; | ||
| 87 | while (length && cnt) { | ||
| 88 | buf[off++] = (host->io_word >> 8) & 0xff; | ||
| 89 | cnt--; | ||
| 90 | length--; | ||
| 91 | } | ||
| 92 | fifo_offset += 4 - cnt; | ||
| 93 | } while (length); | ||
| 94 | |||
| 95 | if (cnt) | ||
| 96 | host->cmd_flags |= DATA_CARRY; | ||
| 97 | |||
| 98 | kunmap_atomic(buf - page_off, KM_BIO_DST_IRQ); | ||
| 99 | } | 122 | } |
| 100 | 123 | ||
| 101 | static void tifm_ms_write_fifo(struct tifm_ms *host, unsigned int fifo_offset, | 124 | static unsigned int tifm_ms_write_data(struct tifm_ms *host, |
| 102 | struct page *pg, unsigned int page_off, | 125 | unsigned char *buf, unsigned int length) |
| 103 | unsigned int length) | ||
| 104 | { | 126 | { |
| 105 | struct tifm_dev *sock = host->dev; | 127 | struct tifm_dev *sock = host->dev; |
| 106 | unsigned int cnt = 0, off = 0; | 128 | unsigned int off = 0; |
| 107 | unsigned char *buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + page_off; | ||
| 108 | 129 | ||
| 109 | if (host->cmd_flags & DATA_CARRY) { | 130 | if (host->io_pos) { |
| 110 | while (fifo_offset & 3) { | 131 | while (host->io_pos < 4 && length) { |
| 111 | host->io_word |= buf[off++] << (8 * (fifo_offset & 3)); | 132 | host->io_word |= buf[off++] << (host->io_pos * 8); |
| 133 | host->io_pos++; | ||
| 112 | length--; | 134 | length--; |
| 113 | fifo_offset++; | ||
| 114 | } | 135 | } |
| 115 | if (!(fifo_offset & 3)) { | ||
| 116 | writel(host->io_word, sock->addr + SOCK_FIFO_ACCESS | ||
| 117 | + fifo_offset - 4); | ||
| 118 | |||
| 119 | host->cmd_flags &= ~DATA_CARRY; | ||
| 120 | } | ||
| 121 | if (!length) | ||
| 122 | return; | ||
| 123 | } | 136 | } |
| 124 | 137 | ||
| 125 | do { | 138 | if (host->io_pos == 4 |
| 126 | cnt = 4; | 139 | && !(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) { |
| 140 | writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM), | ||
| 141 | sock->addr + SOCK_MS_SYSTEM); | ||
| 142 | writel(host->io_word, sock->addr + SOCK_MS_DATA); | ||
| 143 | host->io_pos = 0; | ||
| 127 | host->io_word = 0; | 144 | host->io_word = 0; |
| 128 | while (length && cnt) { | 145 | } else if (host->io_pos) { |
| 129 | host->io_word |= buf[off++] << (4 - cnt); | 146 | return off; |
| 130 | cnt--; | 147 | } |
| 131 | length--; | ||
| 132 | } | ||
| 133 | fifo_offset += 4 - cnt; | ||
| 134 | if (!cnt) | ||
| 135 | writel(host->io_word, sock->addr + SOCK_FIFO_ACCESS | ||
| 136 | + fifo_offset - 4); | ||
| 137 | |||
| 138 | } while (length); | ||
| 139 | |||
| 140 | if (cnt) | ||
| 141 | host->cmd_flags |= DATA_CARRY; | ||
| 142 | 148 | ||
| 143 | kunmap_atomic(buf - page_off, KM_BIO_SRC_IRQ); | 149 | if (!length) |
| 144 | } | 150 | return off; |
| 145 | 151 | ||
| 146 | static void tifm_ms_move_block(struct tifm_ms *host, unsigned int length) | 152 | while (!(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) { |
| 147 | { | 153 | if (length < 4) |
| 148 | unsigned int t_size; | 154 | break; |
| 149 | unsigned int off = host->req->sg.offset + host->block_pos; | 155 | writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM), |
| 150 | unsigned int p_off, p_cnt; | 156 | sock->addr + SOCK_MS_SYSTEM); |
| 151 | struct page *pg; | 157 | __raw_writel(*(unsigned int *)(buf + off), |
| 152 | unsigned long flags; | 158 | sock->addr + SOCK_MS_DATA); |
| 159 | length -= 4; | ||
| 160 | off += 4; | ||
| 161 | } | ||
| 153 | 162 | ||
| 154 | dev_dbg(&host->dev->dev, "moving block\n"); | 163 | switch (length) { |
| 155 | local_irq_save(flags); | 164 | case 3: |
| 156 | t_size = length; | 165 | host->io_word |= buf[off + 2] << 16; |
| 157 | while (t_size) { | 166 | host->io_pos++; |
| 158 | pg = nth_page(sg_page(&host->req->sg), off >> PAGE_SHIFT); | 167 | case 2: |
| 159 | p_off = offset_in_page(off); | 168 | host->io_word |= buf[off + 1] << 8; |
| 160 | p_cnt = PAGE_SIZE - p_off; | 169 | host->io_pos++; |
| 161 | p_cnt = min(p_cnt, t_size); | 170 | case 1: |
| 171 | host->io_word |= buf[off]; | ||
| 172 | host->io_pos++; | ||
| 173 | } | ||
| 162 | 174 | ||
| 163 | if (host->req->data_dir == WRITE) | 175 | off += host->io_pos; |
| 164 | tifm_ms_write_fifo(host, length - t_size, | ||
| 165 | pg, p_off, p_cnt); | ||
| 166 | else | ||
| 167 | tifm_ms_read_fifo(host, length - t_size, | ||
| 168 | pg, p_off, p_cnt); | ||
| 169 | 176 | ||
| 170 | t_size -= p_cnt; | 177 | return off; |
| 171 | } | ||
| 172 | local_irq_restore(flags); | ||
| 173 | } | 178 | } |
| 174 | 179 | ||
| 175 | static int tifm_ms_transfer_data(struct tifm_ms *host, int skip) | 180 | static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) |
| 176 | { | 181 | { |
| 177 | struct tifm_dev *sock = host->dev; | 182 | struct tifm_dev *sock = host->dev; |
| 178 | unsigned int length = host->req->sg.length - host->block_pos; | 183 | unsigned int length; |
| 184 | unsigned int off; | ||
| 185 | unsigned int t_size, p_off, p_cnt; | ||
| 186 | unsigned char *buf; | ||
| 187 | struct page *pg; | ||
| 188 | unsigned long flags = 0; | ||
| 189 | |||
| 190 | if (host->req->long_data) { | ||
| 191 | length = host->req->sg.length - host->block_pos; | ||
| 192 | off = host->req->sg.offset + host->block_pos; | ||
| 193 | } else { | ||
| 194 | length = host->req->data_len - host->block_pos; | ||
| 195 | off = 0; | ||
| 196 | } | ||
| 197 | dev_dbg(&sock->dev, "fifo data transfer, %d, %d\n", length, | ||
| 198 | host->block_pos); | ||
| 199 | |||
| 200 | while (length) { | ||
| 201 | if (host->req->long_data) { | ||
| 202 | pg = nth_page(sg_page(&host->req->sg), | ||
| 203 | off >> PAGE_SHIFT); | ||
| 204 | p_off = offset_in_page(off); | ||
| 205 | p_cnt = PAGE_SIZE - p_off; | ||
| 206 | p_cnt = min(p_cnt, length); | ||
| 207 | |||
| 208 | local_irq_save(flags); | ||
| 209 | buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; | ||
| 210 | } else { | ||
| 211 | buf = host->req->data + host->block_pos; | ||
| 212 | p_cnt = host->req->data_len - host->block_pos; | ||
| 213 | } | ||
| 179 | 214 | ||
| 180 | if (!length) | 215 | t_size = host->req->data_dir == WRITE |
| 181 | return 1; | 216 | ? tifm_ms_write_data(host, buf, p_cnt) |
| 217 | : tifm_ms_read_data(host, buf, p_cnt); | ||
| 182 | 218 | ||
| 183 | if (length > TIFM_FIFO_SIZE) | 219 | if (host->req->long_data) { |
| 184 | length = TIFM_FIFO_SIZE; | 220 | kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); |
| 221 | local_irq_restore(flags); | ||
| 222 | } | ||
| 185 | 223 | ||
| 186 | if (!skip) { | 224 | if (!t_size) |
| 187 | tifm_ms_move_block(host, length); | 225 | break; |
| 188 | host->block_pos += length; | 226 | host->block_pos += t_size; |
| 227 | length -= t_size; | ||
| 228 | off += t_size; | ||
| 189 | } | 229 | } |
| 190 | 230 | ||
| 191 | if ((host->req->data_dir == READ) | 231 | dev_dbg(&sock->dev, "fifo data transfer, %d remaining\n", length); |
| 192 | && (host->block_pos == host->req->sg.length)) | 232 | if (!length && (host->req->data_dir == WRITE)) { |
| 193 | return 1; | 233 | if (host->io_pos) { |
| 194 | 234 | writel(TIFM_MS_SYS_FDIR | |
| 195 | writel(ilog2(length) - 2, sock->addr + SOCK_FIFO_PAGE_SIZE); | 235 | | readl(sock->addr + SOCK_MS_SYSTEM), |
| 196 | if (host->req->data_dir == WRITE) | 236 | sock->addr + SOCK_MS_SYSTEM); |
| 197 | writel((1 << 8) | TIFM_DMA_TX, sock->addr + SOCK_DMA_CONTROL); | 237 | writel(host->io_word, sock->addr + SOCK_MS_DATA); |
| 198 | else | 238 | } |
| 199 | writel((1 << 8), sock->addr + SOCK_DMA_CONTROL); | 239 | writel(TIFM_MS_SYS_FDIR |
| 240 | | readl(sock->addr + SOCK_MS_SYSTEM), | ||
| 241 | sock->addr + SOCK_MS_SYSTEM); | ||
| 242 | writel(0, sock->addr + SOCK_MS_DATA); | ||
| 243 | } else { | ||
| 244 | readl(sock->addr + SOCK_MS_DATA); | ||
| 245 | } | ||
| 200 | 246 | ||
| 201 | return 0; | 247 | return length; |
| 202 | } | 248 | } |
| 203 | 249 | ||
| 204 | static int tifm_ms_issue_cmd(struct tifm_ms *host) | 250 | static int tifm_ms_issue_cmd(struct tifm_ms *host) |
| 205 | { | 251 | { |
| 206 | struct tifm_dev *sock = host->dev; | 252 | struct tifm_dev *sock = host->dev; |
| 207 | unsigned char *data; | 253 | unsigned char *data; |
| 208 | unsigned int data_len = 0, cmd = 0, cmd_mask = 0, cnt, tval = 0; | 254 | unsigned int data_len, cmd, sys_param; |
| 209 | 255 | ||
| 210 | host->cmd_flags = 0; | 256 | host->cmd_flags = 0; |
| 257 | host->block_pos = 0; | ||
| 258 | host->io_pos = 0; | ||
| 259 | host->io_word = 0; | ||
| 260 | host->cmd_flags = 0; | ||
| 211 | 261 | ||
| 212 | if (host->req->io_type == MEMSTICK_IO_SG) { | 262 | data = host->req->data; |
| 213 | if (!host->no_dma) { | ||
| 214 | if (1 != tifm_map_sg(sock, &host->req->sg, 1, | ||
| 215 | host->req->data_dir == READ | ||
| 216 | ? PCI_DMA_FROMDEVICE | ||
| 217 | : PCI_DMA_TODEVICE)) { | ||
| 218 | host->req->error = -ENOMEM; | ||
| 219 | return host->req->error; | ||
| 220 | } | ||
| 221 | data_len = sg_dma_len(&host->req->sg); | ||
| 222 | } else | ||
| 223 | data_len = host->req->sg.length; | ||
| 224 | |||
| 225 | writel(TIFM_FIFO_INT_SETALL, | ||
| 226 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); | ||
| 227 | writel(TIFM_FIFO_ENABLE, | ||
| 228 | sock->addr + SOCK_FIFO_CONTROL); | ||
| 229 | writel(TIFM_FIFO_INTMASK, | ||
| 230 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); | ||
| 231 | 263 | ||
| 232 | if (!host->no_dma) { | 264 | host->use_dma = !no_dma; |
| 233 | writel(ilog2(data_len) - 2, | ||
| 234 | sock->addr + SOCK_FIFO_PAGE_SIZE); | ||
| 235 | writel(sg_dma_address(&host->req->sg), | ||
| 236 | sock->addr + SOCK_DMA_ADDRESS); | ||
| 237 | if (host->req->data_dir == WRITE) | ||
| 238 | writel((1 << 8) | TIFM_DMA_TX | TIFM_DMA_EN, | ||
| 239 | sock->addr + SOCK_DMA_CONTROL); | ||
| 240 | else | ||
| 241 | writel((1 << 8) | TIFM_DMA_EN, | ||
| 242 | sock->addr + SOCK_DMA_CONTROL); | ||
| 243 | } else { | ||
| 244 | tifm_ms_transfer_data(host, | ||
| 245 | host->req->data_dir == READ); | ||
| 246 | } | ||
| 247 | 265 | ||
| 248 | cmd_mask = readl(sock->addr + SOCK_MS_SYSTEM); | 266 | if (host->req->long_data) { |
| 249 | cmd_mask |= TIFM_MS_SYS_DATA | TIFM_MS_SYS_NOT_RDY; | 267 | data_len = host->req->sg.length; |
| 250 | writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); | 268 | if (!is_power_of_2(data_len)) |
| 251 | } else if (host->req->io_type == MEMSTICK_IO_VAL) { | 269 | host->use_dma = 0; |
| 252 | data = host->req->data; | 270 | } else { |
| 253 | data_len = host->req->data_len; | 271 | data_len = host->req->data_len; |
| 272 | host->use_dma = 0; | ||
| 273 | } | ||
| 254 | 274 | ||
| 255 | cmd_mask = host->mode_mask | 0x2607; /* unknown constant */ | 275 | writel(TIFM_FIFO_INT_SETALL, |
| 256 | 276 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); | |
| 257 | if (host->req->data_dir == WRITE) { | 277 | writel(TIFM_FIFO_ENABLE, |
| 258 | cmd_mask |= TIFM_MS_SYS_LATCH; | 278 | sock->addr + SOCK_FIFO_CONTROL); |
| 259 | writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); | 279 | |
| 260 | for (cnt = 0; (data_len - cnt) >= 4; cnt += 4) { | 280 | if (host->use_dma) { |
| 261 | writel(TIFM_MS_SYS_LATCH | 281 | if (1 != tifm_map_sg(sock, &host->req->sg, 1, |
| 262 | | readl(sock->addr + SOCK_MS_SYSTEM), | 282 | host->req->data_dir == READ |
| 263 | sock->addr + SOCK_MS_SYSTEM); | 283 | ? PCI_DMA_FROMDEVICE |
| 264 | __raw_writel(*(unsigned int *)(data + cnt), | 284 | : PCI_DMA_TODEVICE)) { |
| 265 | sock->addr + SOCK_MS_DATA); | 285 | host->req->error = -ENOMEM; |
| 266 | dev_dbg(&sock->dev, "writing %x\n", | 286 | return host->req->error; |
| 267 | *(int *)(data + cnt)); | 287 | } |
| 268 | } | 288 | data_len = sg_dma_len(&host->req->sg); |
| 269 | switch (data_len - cnt) { | ||
| 270 | case 3: | ||
| 271 | tval |= data[cnt + 2] << 16; | ||
| 272 | case 2: | ||
| 273 | tval |= data[cnt + 1] << 8; | ||
| 274 | case 1: | ||
| 275 | tval |= data[cnt]; | ||
| 276 | writel(TIFM_MS_SYS_LATCH | ||
| 277 | | readl(sock->addr + SOCK_MS_SYSTEM), | ||
| 278 | sock->addr + SOCK_MS_SYSTEM); | ||
| 279 | writel(tval, sock->addr + SOCK_MS_DATA); | ||
| 280 | dev_dbg(&sock->dev, "writing %x\n", tval); | ||
| 281 | } | ||
| 282 | 289 | ||
| 283 | writel(TIFM_MS_SYS_LATCH | 290 | writel(ilog2(data_len) - 2, |
| 284 | | readl(sock->addr + SOCK_MS_SYSTEM), | 291 | sock->addr + SOCK_FIFO_PAGE_SIZE); |
| 285 | sock->addr + SOCK_MS_SYSTEM); | 292 | writel(TIFM_FIFO_INTMASK, |
| 286 | writel(0, sock->addr + SOCK_MS_DATA); | 293 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); |
| 287 | dev_dbg(&sock->dev, "writing %x\n", 0); | 294 | sys_param = TIFM_DMA_EN | (1 << 8); |
| 295 | if (host->req->data_dir == WRITE) | ||
| 296 | sys_param |= TIFM_DMA_TX; | ||
| 297 | |||
| 298 | writel(TIFM_FIFO_INTMASK, | ||
| 299 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); | ||
| 288 | 300 | ||
| 289 | } else | 301 | writel(sg_dma_address(&host->req->sg), |
| 290 | writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); | 302 | sock->addr + SOCK_DMA_ADDRESS); |
| 303 | writel(sys_param, sock->addr + SOCK_DMA_CONTROL); | ||
| 304 | } else { | ||
| 305 | writel(host->mode_mask | TIFM_MS_SYS_FIFO, | ||
| 306 | sock->addr + SOCK_MS_SYSTEM); | ||
| 291 | 307 | ||
| 292 | cmd_mask = readl(sock->addr + SOCK_MS_SYSTEM); | 308 | writel(TIFM_FIFO_MORE, |
| 293 | cmd_mask &= ~TIFM_MS_SYS_DATA; | 309 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); |
| 294 | cmd_mask |= TIFM_MS_SYS_NOT_RDY; | 310 | } |
| 295 | dev_dbg(&sock->dev, "mask %x\n", cmd_mask); | ||
| 296 | writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); | ||
| 297 | } else | ||
| 298 | BUG(); | ||
| 299 | 311 | ||
| 300 | mod_timer(&host->timer, jiffies + host->timeout_jiffies); | 312 | mod_timer(&host->timer, jiffies + host->timeout_jiffies); |
| 301 | writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), | 313 | writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), |
| 302 | sock->addr + SOCK_CONTROL); | 314 | sock->addr + SOCK_CONTROL); |
| 303 | host->req->error = 0; | 315 | host->req->error = 0; |
| 304 | 316 | ||
| 317 | sys_param = readl(sock->addr + SOCK_MS_SYSTEM); | ||
| 318 | sys_param |= TIFM_MS_SYS_INTCLR; | ||
| 319 | |||
| 320 | if (host->use_dma) | ||
| 321 | sys_param |= TIFM_MS_SYS_DMA; | ||
| 322 | else | ||
| 323 | sys_param &= ~TIFM_MS_SYS_DMA; | ||
| 324 | |||
| 325 | writel(sys_param, sock->addr + SOCK_MS_SYSTEM); | ||
| 326 | |||
| 305 | cmd = (host->req->tpc & 0xf) << 12; | 327 | cmd = (host->req->tpc & 0xf) << 12; |
| 306 | cmd |= data_len; | 328 | cmd |= data_len; |
| 307 | writel(cmd, sock->addr + SOCK_MS_COMMAND); | 329 | writel(cmd, sock->addr + SOCK_MS_COMMAND); |
| 308 | 330 | ||
| 309 | dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, cmd_mask); | 331 | dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, sys_param); |
| 310 | return 0; | 332 | return 0; |
| 311 | } | 333 | } |
| 312 | 334 | ||
| @@ -314,47 +336,20 @@ static void tifm_ms_complete_cmd(struct tifm_ms *host) | |||
| 314 | { | 336 | { |
| 315 | struct tifm_dev *sock = host->dev; | 337 | struct tifm_dev *sock = host->dev; |
| 316 | struct memstick_host *msh = tifm_get_drvdata(sock); | 338 | struct memstick_host *msh = tifm_get_drvdata(sock); |
| 317 | unsigned int tval = 0, data_len; | ||
| 318 | unsigned char *data; | ||
| 319 | int rc; | 339 | int rc; |
| 320 | 340 | ||
| 321 | del_timer(&host->timer); | 341 | del_timer(&host->timer); |
| 322 | if (host->req->io_type == MEMSTICK_IO_SG) { | ||
| 323 | if (!host->no_dma) | ||
| 324 | tifm_unmap_sg(sock, &host->req->sg, 1, | ||
| 325 | host->req->data_dir == READ | ||
| 326 | ? PCI_DMA_FROMDEVICE | ||
| 327 | : PCI_DMA_TODEVICE); | ||
| 328 | } else if (host->req->io_type == MEMSTICK_IO_VAL) { | ||
| 329 | writel(~TIFM_MS_SYS_DATA & readl(sock->addr + SOCK_MS_SYSTEM), | ||
| 330 | sock->addr + SOCK_MS_SYSTEM); | ||
| 331 | |||
| 332 | data = host->req->data; | ||
| 333 | data_len = host->req->data_len; | ||
| 334 | 342 | ||
| 335 | if (host->req->data_dir == READ) { | 343 | if (host->use_dma) |
| 336 | for (rc = 0; (data_len - rc) >= 4; rc += 4) | 344 | tifm_unmap_sg(sock, &host->req->sg, 1, |
| 337 | *(int *)(data + rc) | 345 | host->req->data_dir == READ |
| 338 | = __raw_readl(sock->addr | 346 | ? PCI_DMA_FROMDEVICE |
| 339 | + SOCK_MS_DATA); | 347 | : PCI_DMA_TODEVICE); |
| 340 | |||
| 341 | if (data_len - rc) | ||
| 342 | tval = readl(sock->addr + SOCK_MS_DATA); | ||
| 343 | switch (data_len - rc) { | ||
| 344 | case 3: | ||
| 345 | data[rc + 2] = (tval >> 16) & 0xff; | ||
| 346 | case 2: | ||
| 347 | data[rc + 1] = (tval >> 8) & 0xff; | ||
| 348 | case 1: | ||
| 349 | data[rc] = tval & 0xff; | ||
| 350 | } | ||
| 351 | readl(sock->addr + SOCK_MS_DATA); | ||
| 352 | } | ||
| 353 | } | ||
| 354 | 348 | ||
| 355 | writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), | 349 | writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), |
| 356 | sock->addr + SOCK_CONTROL); | 350 | sock->addr + SOCK_CONTROL); |
| 357 | 351 | ||
| 352 | dev_dbg(&sock->dev, "TPC complete\n"); | ||
| 358 | do { | 353 | do { |
| 359 | rc = memstick_next_req(msh, &host->req); | 354 | rc = memstick_next_req(msh, &host->req); |
| 360 | } while (!rc && tifm_ms_issue_cmd(host)); | 355 | } while (!rc && tifm_ms_issue_cmd(host)); |
| @@ -365,11 +360,10 @@ static int tifm_ms_check_status(struct tifm_ms *host) | |||
| 365 | if (!host->req->error) { | 360 | if (!host->req->error) { |
| 366 | if (!(host->cmd_flags & CMD_READY)) | 361 | if (!(host->cmd_flags & CMD_READY)) |
| 367 | return 1; | 362 | return 1; |
| 368 | if ((host->req->io_type == MEMSTICK_IO_SG) | 363 | if (!(host->cmd_flags & FIFO_READY)) |
| 369 | && !(host->cmd_flags & FIFO_READY)) | ||
| 370 | return 1; | 364 | return 1; |
| 371 | if (host->req->need_card_int | 365 | if (host->req->need_card_int |
| 372 | && !(host->cmd_flags & CARD_READY)) | 366 | && !(host->cmd_flags & CARD_INT)) |
| 373 | return 1; | 367 | return 1; |
| 374 | } | 368 | } |
| 375 | return 0; | 369 | return 0; |
| @@ -379,18 +373,24 @@ static int tifm_ms_check_status(struct tifm_ms *host) | |||
| 379 | static void tifm_ms_data_event(struct tifm_dev *sock) | 373 | static void tifm_ms_data_event(struct tifm_dev *sock) |
| 380 | { | 374 | { |
| 381 | struct tifm_ms *host; | 375 | struct tifm_ms *host; |
| 382 | unsigned int fifo_status = 0; | 376 | unsigned int fifo_status = 0, host_status = 0; |
| 383 | int rc = 1; | 377 | int rc = 1; |
| 384 | 378 | ||
| 385 | spin_lock(&sock->lock); | 379 | spin_lock(&sock->lock); |
| 386 | host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock)); | 380 | host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock)); |
| 387 | fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); | 381 | fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); |
| 388 | dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n", | 382 | host_status = readl(sock->addr + SOCK_MS_STATUS); |
| 389 | fifo_status, host->cmd_flags); | 383 | dev_dbg(&sock->dev, |
| 384 | "data event: fifo_status %x, host_status %x, flags %x\n", | ||
| 385 | fifo_status, host_status, host->cmd_flags); | ||
| 390 | 386 | ||
| 391 | if (host->req) { | 387 | if (host->req) { |
| 392 | if (fifo_status & TIFM_FIFO_READY) { | 388 | if (host->use_dma && (fifo_status & 1)) { |
| 393 | if (!host->no_dma || tifm_ms_transfer_data(host, 0)) { | 389 | host->cmd_flags |= FIFO_READY; |
| 390 | rc = tifm_ms_check_status(host); | ||
| 391 | } | ||
| 392 | if (!host->use_dma && (fifo_status & TIFM_FIFO_MORE)) { | ||
| 393 | if (!tifm_ms_transfer_data(host)) { | ||
| 394 | host->cmd_flags |= FIFO_READY; | 394 | host->cmd_flags |= FIFO_READY; |
| 395 | rc = tifm_ms_check_status(host); | 395 | rc = tifm_ms_check_status(host); |
| 396 | } | 396 | } |
| @@ -419,9 +419,9 @@ static void tifm_ms_card_event(struct tifm_dev *sock) | |||
| 419 | host_status, host->cmd_flags); | 419 | host_status, host->cmd_flags); |
| 420 | 420 | ||
| 421 | if (host->req) { | 421 | if (host->req) { |
| 422 | if (host_status & TIFM_MS_TIMEOUT) | 422 | if (host_status & TIFM_MS_STAT_TOE) |
| 423 | host->req->error = -ETIME; | 423 | host->req->error = -ETIME; |
| 424 | else if (host_status & TIFM_MS_BADCRC) | 424 | else if (host_status & TIFM_MS_STAT_CRC) |
| 425 | host->req->error = -EILSEQ; | 425 | host->req->error = -EILSEQ; |
| 426 | 426 | ||
| 427 | if (host->req->error) { | 427 | if (host->req->error) { |
| @@ -430,18 +430,17 @@ static void tifm_ms_card_event(struct tifm_dev *sock) | |||
| 430 | writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); | 430 | writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | if (host_status & TIFM_MS_EOTPC) | 433 | if (host_status & TIFM_MS_STAT_RDY) |
| 434 | host->cmd_flags |= CMD_READY; | 434 | host->cmd_flags |= CMD_READY; |
| 435 | if (host_status & TIFM_MS_INT) | 435 | |
| 436 | host->cmd_flags |= CARD_READY; | 436 | if (host_status & TIFM_MS_STAT_MSINT) |
| 437 | host->cmd_flags |= CARD_INT; | ||
| 437 | 438 | ||
| 438 | rc = tifm_ms_check_status(host); | 439 | rc = tifm_ms_check_status(host); |
| 439 | 440 | ||
| 440 | } | 441 | } |
| 441 | 442 | ||
| 442 | writel(TIFM_MS_SYS_NOT_RDY | readl(sock->addr + SOCK_MS_SYSTEM), | 443 | writel(TIFM_MS_SYS_INTCLR | readl(sock->addr + SOCK_MS_SYSTEM), |
| 443 | sock->addr + SOCK_MS_SYSTEM); | ||
| 444 | writel((~TIFM_MS_SYS_DATA) & readl(sock->addr + SOCK_MS_SYSTEM), | ||
| 445 | sock->addr + SOCK_MS_SYSTEM); | 444 | sock->addr + SOCK_MS_SYSTEM); |
| 446 | 445 | ||
| 447 | if (!rc) | 446 | if (!rc) |
| @@ -497,15 +496,26 @@ static void tifm_ms_set_param(struct memstick_host *msh, | |||
| 497 | 496 | ||
| 498 | switch (param) { | 497 | switch (param) { |
| 499 | case MEMSTICK_POWER: | 498 | case MEMSTICK_POWER: |
| 500 | /* this is set by card detection mechanism */ | 499 | /* also affected by media detection mechanism */ |
| 500 | if (value == MEMSTICK_POWER_ON) { | ||
| 501 | host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI; | ||
| 502 | writel(TIFM_MS_SYS_RESET, sock->addr + SOCK_MS_SYSTEM); | ||
| 503 | writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, | ||
| 504 | sock->addr + SOCK_MS_SYSTEM); | ||
| 505 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); | ||
| 506 | } else if (value == MEMSTICK_POWER_OFF) { | ||
| 507 | writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, | ||
| 508 | sock->addr + SOCK_MS_SYSTEM); | ||
| 509 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); | ||
| 510 | } | ||
| 501 | break; | 511 | break; |
| 502 | case MEMSTICK_INTERFACE: | 512 | case MEMSTICK_INTERFACE: |
| 503 | if (value == MEMSTICK_SERIAL) { | 513 | if (value == MEMSTICK_SERIAL) { |
| 504 | host->mode_mask = TIFM_MS_SERIAL; | 514 | host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI; |
| 505 | writel((~TIFM_CTRL_FAST_CLK) | 515 | writel((~TIFM_CTRL_FAST_CLK) |
| 506 | & readl(sock->addr + SOCK_CONTROL), | 516 | & readl(sock->addr + SOCK_CONTROL), |
| 507 | sock->addr + SOCK_CONTROL); | 517 | sock->addr + SOCK_CONTROL); |
| 508 | } else if (value == MEMSTICK_PARALLEL) { | 518 | } else if (value == MEMSTICK_PAR4) { |
| 509 | host->mode_mask = 0; | 519 | host->mode_mask = 0; |
| 510 | writel(TIFM_CTRL_FAST_CLK | 520 | writel(TIFM_CTRL_FAST_CLK |
| 511 | | readl(sock->addr + SOCK_CONTROL), | 521 | | readl(sock->addr + SOCK_CONTROL), |
| @@ -532,21 +542,6 @@ static void tifm_ms_abort(unsigned long data) | |||
| 532 | tifm_eject(host->dev); | 542 | tifm_eject(host->dev); |
| 533 | } | 543 | } |
| 534 | 544 | ||
| 535 | static int tifm_ms_initialize_host(struct tifm_ms *host) | ||
| 536 | { | ||
| 537 | struct tifm_dev *sock = host->dev; | ||
| 538 | struct memstick_host *msh = tifm_get_drvdata(sock); | ||
| 539 | |||
| 540 | host->mode_mask = TIFM_MS_SERIAL; | ||
| 541 | writel(0x8000, sock->addr + SOCK_MS_SYSTEM); | ||
| 542 | writel(0x0200 | TIFM_MS_SYS_NOT_RDY, sock->addr + SOCK_MS_SYSTEM); | ||
| 543 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); | ||
| 544 | if (tifm_has_ms_pif(sock)) | ||
| 545 | msh->caps |= MEMSTICK_CAP_PARALLEL; | ||
| 546 | |||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | static int tifm_ms_probe(struct tifm_dev *sock) | 545 | static int tifm_ms_probe(struct tifm_dev *sock) |
| 551 | { | 546 | { |
| 552 | struct memstick_host *msh; | 547 | struct memstick_host *msh; |
| @@ -568,7 +563,6 @@ static int tifm_ms_probe(struct tifm_dev *sock) | |||
| 568 | tifm_set_drvdata(sock, msh); | 563 | tifm_set_drvdata(sock, msh); |
| 569 | host->dev = sock; | 564 | host->dev = sock; |
| 570 | host->timeout_jiffies = msecs_to_jiffies(1000); | 565 | host->timeout_jiffies = msecs_to_jiffies(1000); |
| 571 | host->no_dma = no_dma; | ||
| 572 | 566 | ||
| 573 | setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); | 567 | setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); |
| 574 | 568 | ||
| @@ -576,10 +570,10 @@ static int tifm_ms_probe(struct tifm_dev *sock) | |||
| 576 | msh->set_param = tifm_ms_set_param; | 570 | msh->set_param = tifm_ms_set_param; |
| 577 | sock->card_event = tifm_ms_card_event; | 571 | sock->card_event = tifm_ms_card_event; |
| 578 | sock->data_event = tifm_ms_data_event; | 572 | sock->data_event = tifm_ms_data_event; |
| 579 | rc = tifm_ms_initialize_host(host); | 573 | if (tifm_has_ms_pif(sock)) |
| 574 | msh->caps |= MEMSTICK_CAP_PAR4; | ||
| 580 | 575 | ||
| 581 | if (!rc) | 576 | rc = memstick_add_host(msh); |
| 582 | rc = memstick_add_host(msh); | ||
| 583 | if (!rc) | 577 | if (!rc) |
| 584 | return 0; | 578 | return 0; |
| 585 | 579 | ||
| @@ -601,7 +595,7 @@ static void tifm_ms_remove(struct tifm_dev *sock) | |||
| 601 | writel(TIFM_FIFO_INT_SETALL, | 595 | writel(TIFM_FIFO_INT_SETALL, |
| 602 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); | 596 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); |
| 603 | writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); | 597 | writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); |
| 604 | if ((host->req->io_type == MEMSTICK_IO_SG) && !host->no_dma) | 598 | if (host->use_dma) |
| 605 | tifm_unmap_sg(sock, &host->req->sg, 1, | 599 | tifm_unmap_sg(sock, &host->req->sg, 1, |
| 606 | host->req->data_dir == READ | 600 | host->req->data_dir == READ |
| 607 | ? PCI_DMA_TODEVICE | 601 | ? PCI_DMA_TODEVICE |
| @@ -617,10 +611,6 @@ static void tifm_ms_remove(struct tifm_dev *sock) | |||
| 617 | spin_unlock_irqrestore(&sock->lock, flags); | 611 | spin_unlock_irqrestore(&sock->lock, flags); |
| 618 | 612 | ||
| 619 | memstick_remove_host(msh); | 613 | memstick_remove_host(msh); |
| 620 | |||
| 621 | writel(0x0200 | TIFM_MS_SYS_NOT_RDY, sock->addr + SOCK_MS_SYSTEM); | ||
| 622 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); | ||
| 623 | |||
| 624 | memstick_free_host(msh); | 614 | memstick_free_host(msh); |
| 625 | } | 615 | } |
| 626 | 616 | ||
| @@ -628,17 +618,17 @@ static void tifm_ms_remove(struct tifm_dev *sock) | |||
| 628 | 618 | ||
| 629 | static int tifm_ms_suspend(struct tifm_dev *sock, pm_message_t state) | 619 | static int tifm_ms_suspend(struct tifm_dev *sock, pm_message_t state) |
| 630 | { | 620 | { |
| 621 | struct memstick_host *msh = tifm_get_drvdata(sock); | ||
| 622 | |||
| 623 | memstick_suspend_host(msh); | ||
| 631 | return 0; | 624 | return 0; |
| 632 | } | 625 | } |
| 633 | 626 | ||
| 634 | static int tifm_ms_resume(struct tifm_dev *sock) | 627 | static int tifm_ms_resume(struct tifm_dev *sock) |
| 635 | { | 628 | { |
| 636 | struct memstick_host *msh = tifm_get_drvdata(sock); | 629 | struct memstick_host *msh = tifm_get_drvdata(sock); |
| 637 | struct tifm_ms *host = memstick_priv(msh); | ||
| 638 | |||
| 639 | tifm_ms_initialize_host(host); | ||
| 640 | memstick_detect_change(msh); | ||
| 641 | 630 | ||
| 631 | memstick_resume_host(msh); | ||
| 642 | return 0; | 632 | return 0; |
| 643 | } | 633 | } |
| 644 | 634 | ||
| @@ -679,7 +669,6 @@ MODULE_AUTHOR("Alex Dubov"); | |||
| 679 | MODULE_DESCRIPTION("TI FlashMedia MemoryStick driver"); | 669 | MODULE_DESCRIPTION("TI FlashMedia MemoryStick driver"); |
| 680 | MODULE_LICENSE("GPL"); | 670 | MODULE_LICENSE("GPL"); |
| 681 | MODULE_DEVICE_TABLE(tifm, tifm_ms_id_tbl); | 671 | MODULE_DEVICE_TABLE(tifm, tifm_ms_id_tbl); |
| 682 | MODULE_VERSION(DRIVER_VERSION); | ||
| 683 | 672 | ||
| 684 | module_init(tifm_ms_init); | 673 | module_init(tifm_ms_init); |
| 685 | module_exit(tifm_ms_exit); | 674 | module_exit(tifm_ms_exit); |
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 63a089b29545..67503ea71d21 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
| @@ -368,6 +368,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
| 368 | goto err_out_irq; | 368 | goto err_out_irq; |
| 369 | 369 | ||
| 370 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), | 370 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), |
| 371 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
| 372 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), | ||
| 371 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 373 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
| 372 | return 0; | 374 | return 0; |
| 373 | 375 | ||
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index a64d85821996..c0e50a461055 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c | |||
| @@ -138,7 +138,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { | |||
| 138 | { /* end of list */ }, | 138 | { /* end of list */ }, |
| 139 | }; | 139 | }; |
| 140 | 140 | ||
| 141 | static struct of_platform_driver __devinitdata of_platform_serial_driver = { | 141 | static struct of_platform_driver of_platform_serial_driver = { |
| 142 | .owner = THIS_MODULE, | 142 | .owner = THIS_MODULE, |
| 143 | .name = "of_serial", | 143 | .name = "of_serial", |
| 144 | .probe = of_platform_serial_probe, | 144 | .probe = of_platform_serial_probe, |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 758435f8a6f8..e0b0580705e4 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
| @@ -553,6 +553,19 @@ config FB_BF54X_LQ043 | |||
| 553 | help | 553 | help |
| 554 | This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD | 554 | This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD |
| 555 | 555 | ||
| 556 | config FB_BFIN_T350MCQB | ||
| 557 | tristate "Varitronix COG-T350MCQB TFT LCD display (BF527 EZKIT)" | ||
| 558 | depends on FB && BLACKFIN | ||
| 559 | select BFIN_GPTIMERS | ||
| 560 | select FB_CFB_FILLRECT | ||
| 561 | select FB_CFB_COPYAREA | ||
| 562 | select FB_CFB_IMAGEBLIT | ||
| 563 | help | ||
| 564 | This is the framebuffer device driver for a Varitronix VL-PS-COG-T350MCQB-01 display TFT LCD | ||
| 565 | This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI | ||
| 566 | It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. | ||
| 567 | |||
| 568 | |||
| 556 | config FB_STI | 569 | config FB_STI |
| 557 | tristate "HP STI frame buffer device support" | 570 | tristate "HP STI frame buffer device support" |
| 558 | depends on FB && PARISC | 571 | depends on FB && PARISC |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 83e02b3429b6..03371c789039 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
| @@ -122,6 +122,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o | |||
| 122 | obj-$(CONFIG_FB_VGA16) += vga16fb.o | 122 | obj-$(CONFIG_FB_VGA16) += vga16fb.o |
| 123 | obj-$(CONFIG_FB_OF) += offb.o | 123 | obj-$(CONFIG_FB_OF) += offb.o |
| 124 | obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o | 124 | obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o |
| 125 | obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o | ||
| 125 | 126 | ||
| 126 | # the test framebuffer is last | 127 | # the test framebuffer is last |
| 127 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o | 128 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o |
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 0ce791e6f79c..986a550c0439 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * | 8 | * |
| 9 | * | 9 | * |
| 10 | * Modified: | 10 | * Modified: |
| 11 | * Copyright 2004-2007 Analog Devices Inc. | 11 | * Copyright 2007-2008 Analog Devices Inc. |
| 12 | * | 12 | * |
| 13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | 13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ |
| 14 | * | 14 | * |
| @@ -241,7 +241,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) | |||
| 241 | u16 eppi_req_18[] = EPPI0_18; | 241 | u16 eppi_req_18[] = EPPI0_18; |
| 242 | u16 disp = fbi->mach_info->disp; | 242 | u16 disp = fbi->mach_info->disp; |
| 243 | 243 | ||
| 244 | if (gpio_request(disp, NULL)) { | 244 | if (gpio_request(disp, DRIVER_NAME)) { |
| 245 | printk(KERN_ERR "Requesting GPIO %d faild\n", disp); | 245 | printk(KERN_ERR "Requesting GPIO %d faild\n", disp); |
| 246 | return -EFAULT; | 246 | return -EFAULT; |
| 247 | } | 247 | } |
| @@ -672,7 +672,7 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) | |||
| 672 | &bfin_lq043fb_bl_ops); | 672 | &bfin_lq043fb_bl_ops); |
| 673 | bl_dev->props.max_brightness = 255; | 673 | bl_dev->props.max_brightness = 255; |
| 674 | 674 | ||
| 675 | lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); | 675 | lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops); |
| 676 | lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); | 676 | lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); |
| 677 | #endif | 677 | #endif |
| 678 | 678 | ||
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c new file mode 100644 index 000000000000..a2bb2de9e020 --- /dev/null +++ b/drivers/video/bfin-t350mcqb-fb.c | |||
| @@ -0,0 +1,685 @@ | |||
| 1 | /* | ||
| 2 | * File: drivers/video/bfin-t350mcqb-fb.c | ||
| 3 | * Based on: | ||
| 4 | * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> | ||
| 5 | * | ||
| 6 | * Created: | ||
| 7 | * Description: Blackfin LCD Framebufer driver | ||
| 8 | * | ||
| 9 | * | ||
| 10 | * Modified: | ||
| 11 | * Copyright 2004-2007 Analog Devices Inc. | ||
| 12 | * | ||
| 13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
| 14 | * | ||
| 15 | * This program is free software; you can redistribute it and/or modify | ||
| 16 | * it under the terms of the GNU General Public License as published by | ||
| 17 | * the Free Software Foundation; either version 2 of the License, or | ||
| 18 | * (at your option) any later version. | ||
| 19 | * | ||
| 20 | * This program is distributed in the hope that it will be useful, | ||
| 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 23 | * GNU General Public License for more details. | ||
| 24 | * | ||
| 25 | * You should have received a copy of the GNU General Public License | ||
| 26 | * along with this program; if not, see the file COPYING, or write | ||
| 27 | * to the Free Software Foundation, Inc., | ||
| 28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/errno.h> | ||
| 34 | #include <linux/string.h> | ||
| 35 | #include <linux/fb.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <linux/types.h> | ||
| 38 | #include <linux/interrupt.h> | ||
| 39 | #include <linux/device.h> | ||
| 40 | #include <linux/backlight.h> | ||
| 41 | #include <linux/lcd.h> | ||
| 42 | #include <linux/dma-mapping.h> | ||
| 43 | #include <linux/platform_device.h> | ||
| 44 | |||
| 45 | #include <asm/blackfin.h> | ||
| 46 | #include <asm/irq.h> | ||
| 47 | #include <asm/dma-mapping.h> | ||
| 48 | #include <asm/dma.h> | ||
| 49 | #include <asm/portmux.h> | ||
| 50 | #include <asm/gptimers.h> | ||
| 51 | |||
| 52 | #define NO_BL_SUPPORT | ||
| 53 | |||
| 54 | #define LCD_X_RES 320 /* Horizontal Resolution */ | ||
| 55 | #define LCD_Y_RES 240 /* Vertical Resolution */ | ||
| 56 | #define LCD_BPP 24 /* Bit Per Pixel */ | ||
| 57 | |||
| 58 | #define DMA_BUS_SIZE 16 | ||
| 59 | #define LCD_CLK (12*1000*1000) /* 12MHz */ | ||
| 60 | |||
| 61 | #define CLOCKS_PER_PIX 3 | ||
| 62 | |||
| 63 | /* | ||
| 64 | * HS and VS timing parameters (all in number of PPI clk ticks) | ||
| 65 | */ | ||
| 66 | |||
| 67 | #define U_LINE 1 /* Blanking Lines */ | ||
| 68 | |||
| 69 | #define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ | ||
| 70 | #define H_PERIOD (408 * CLOCKS_PER_PIX) /* HS period */ | ||
| 71 | #define H_PULSE 90 /* HS pulse width */ | ||
| 72 | #define H_START 204 /* first valid pixel */ | ||
| 73 | |||
| 74 | #define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ | ||
| 75 | #define V_PULSE (3 * H_PERIOD) /* VS pulse width (1-5 H_PERIODs) */ | ||
| 76 | #define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ | ||
| 77 | |||
| 78 | #define ACTIVE_VIDEO_MEM_OFFSET (U_LINE * H_ACTPIX) | ||
| 79 | |||
| 80 | #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 | ||
| 81 | |||
| 82 | #define DRIVER_NAME "bfin-t350mcqb" | ||
| 83 | static char driver_name[] = DRIVER_NAME; | ||
| 84 | |||
| 85 | struct bfin_t350mcqbfb_info { | ||
| 86 | struct fb_info *fb; | ||
| 87 | struct device *dev; | ||
| 88 | unsigned char *fb_buffer; /* RGB Buffer */ | ||
| 89 | dma_addr_t dma_handle; | ||
| 90 | int lq043_mmap; | ||
| 91 | int lq043_open_cnt; | ||
| 92 | int irq; | ||
| 93 | spinlock_t lock; /* lock */ | ||
| 94 | }; | ||
| 95 | |||
| 96 | static int nocursor; | ||
| 97 | module_param(nocursor, int, 0644); | ||
| 98 | MODULE_PARM_DESC(nocursor, "cursor enable/disable"); | ||
| 99 | |||
| 100 | #define PPI_TX_MODE 0x2 | ||
| 101 | #define PPI_XFER_TYPE_11 0xC | ||
| 102 | #define PPI_PORT_CFG_01 0x10 | ||
| 103 | #define PPI_PACK_EN 0x80 | ||
| 104 | #define PPI_POLS_1 0x8000 | ||
| 105 | |||
| 106 | static void bfin_t350mcqb_config_ppi(struct bfin_t350mcqbfb_info *fbi) | ||
| 107 | { | ||
| 108 | bfin_write_PPI_DELAY(H_START); | ||
| 109 | bfin_write_PPI_COUNT(H_ACTPIX-1); | ||
| 110 | bfin_write_PPI_FRAME(V_LINES); | ||
| 111 | |||
| 112 | bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ | ||
| 113 | PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ | ||
| 114 | PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ | ||
| 115 | PPI_PACK_EN | /* packing enabled PACK_EN */ | ||
| 116 | PPI_POLS_1); /* faling edge syncs POLS */ | ||
| 117 | } | ||
| 118 | |||
| 119 | static inline void bfin_t350mcqb_disable_ppi(void) | ||
| 120 | { | ||
| 121 | bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); | ||
| 122 | } | ||
| 123 | |||
| 124 | static inline void bfin_t350mcqb_enable_ppi(void) | ||
| 125 | { | ||
| 126 | bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); | ||
| 127 | } | ||
| 128 | |||
| 129 | static void bfin_t350mcqb_start_timers(void) | ||
| 130 | { | ||
| 131 | unsigned long flags; | ||
| 132 | |||
| 133 | local_irq_save(flags); | ||
| 134 | enable_gptimers(TIMER1bit); | ||
| 135 | enable_gptimers(TIMER0bit); | ||
| 136 | local_irq_restore(flags); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void bfin_t350mcqb_stop_timers(void) | ||
| 140 | { | ||
| 141 | disable_gptimers(TIMER0bit | TIMER1bit); | ||
| 142 | |||
| 143 | set_gptimer_status(0, TIMER_STATUS_TRUN0 | TIMER_STATUS_TRUN1 | | ||
| 144 | TIMER_STATUS_TIMIL0 | TIMER_STATUS_TIMIL1 | | ||
| 145 | TIMER_STATUS_TOVF0 | TIMER_STATUS_TOVF1); | ||
| 146 | |||
| 147 | } | ||
| 148 | |||
| 149 | static void bfin_t350mcqb_init_timers(void) | ||
| 150 | { | ||
| 151 | |||
| 152 | bfin_t350mcqb_stop_timers(); | ||
| 153 | |||
| 154 | set_gptimer_period(TIMER0_id, H_PERIOD); | ||
| 155 | set_gptimer_pwidth(TIMER0_id, H_PULSE); | ||
| 156 | set_gptimer_config(TIMER0_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | | ||
| 157 | TIMER_TIN_SEL | TIMER_CLK_SEL| | ||
| 158 | TIMER_EMU_RUN); | ||
| 159 | |||
| 160 | set_gptimer_period(TIMER1_id, V_PERIOD); | ||
| 161 | set_gptimer_pwidth(TIMER1_id, V_PULSE); | ||
| 162 | set_gptimer_config(TIMER1_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | | ||
| 163 | TIMER_TIN_SEL | TIMER_CLK_SEL | | ||
| 164 | TIMER_EMU_RUN); | ||
| 165 | |||
| 166 | } | ||
| 167 | |||
| 168 | static void bfin_t350mcqb_config_dma(struct bfin_t350mcqbfb_info *fbi) | ||
| 169 | { | ||
| 170 | |||
| 171 | set_dma_config(CH_PPI, | ||
| 172 | set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, | ||
| 173 | INTR_DISABLE, DIMENSION_2D, | ||
| 174 | DATA_SIZE_16, | ||
| 175 | DMA_NOSYNC_KEEP_DMA_BUF)); | ||
| 176 | set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); | ||
| 177 | set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); | ||
| 178 | set_dma_y_count(CH_PPI, V_LINES); | ||
| 179 | |||
| 180 | set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); | ||
| 181 | set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); | ||
| 182 | |||
| 183 | } | ||
| 184 | |||
| 185 | static int bfin_t350mcqb_request_ports(int action) | ||
| 186 | { | ||
| 187 | u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, | ||
| 188 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, | ||
| 189 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, | ||
| 190 | P_PPI0_D6, P_PPI0_D7, 0}; | ||
| 191 | |||
| 192 | if (action) { | ||
| 193 | if (peripheral_request_list(ppi0_req_8, DRIVER_NAME)) { | ||
| 194 | printk(KERN_ERR "Requesting Peripherals faild\n"); | ||
| 195 | return -EFAULT; | ||
| 196 | } | ||
| 197 | } else | ||
| 198 | peripheral_free_list(ppi0_req_8); | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int bfin_t350mcqb_fb_open(struct fb_info *info, int user) | ||
| 204 | { | ||
| 205 | struct bfin_t350mcqbfb_info *fbi = info->par; | ||
| 206 | |||
| 207 | spin_lock(&fbi->lock); | ||
| 208 | fbi->lq043_open_cnt++; | ||
| 209 | |||
| 210 | if (fbi->lq043_open_cnt <= 1) { | ||
| 211 | |||
| 212 | bfin_t350mcqb_disable_ppi(); | ||
| 213 | SSYNC(); | ||
| 214 | |||
| 215 | bfin_t350mcqb_config_dma(fbi); | ||
| 216 | bfin_t350mcqb_config_ppi(fbi); | ||
| 217 | bfin_t350mcqb_init_timers(); | ||
| 218 | |||
| 219 | /* start dma */ | ||
| 220 | enable_dma(CH_PPI); | ||
| 221 | bfin_t350mcqb_enable_ppi(); | ||
| 222 | bfin_t350mcqb_start_timers(); | ||
| 223 | } | ||
| 224 | |||
| 225 | spin_unlock(&fbi->lock); | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int bfin_t350mcqb_fb_release(struct fb_info *info, int user) | ||
| 231 | { | ||
| 232 | struct bfin_t350mcqbfb_info *fbi = info->par; | ||
| 233 | |||
| 234 | spin_lock(&fbi->lock); | ||
| 235 | |||
| 236 | fbi->lq043_open_cnt--; | ||
| 237 | fbi->lq043_mmap = 0; | ||
| 238 | |||
| 239 | if (fbi->lq043_open_cnt <= 0) { | ||
| 240 | bfin_t350mcqb_disable_ppi(); | ||
| 241 | SSYNC(); | ||
| 242 | disable_dma(CH_PPI); | ||
| 243 | bfin_t350mcqb_stop_timers(); | ||
| 244 | memset(fbi->fb_buffer, 0, info->fix.smem_len); | ||
| 245 | } | ||
| 246 | |||
| 247 | spin_unlock(&fbi->lock); | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var, | ||
| 253 | struct fb_info *info) | ||
| 254 | { | ||
| 255 | |||
| 256 | if (var->bits_per_pixel != LCD_BPP) { | ||
| 257 | pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, | ||
| 258 | var->bits_per_pixel); | ||
| 259 | return -EINVAL; | ||
| 260 | } | ||
| 261 | |||
| 262 | if (info->var.xres != var->xres || info->var.yres != var->yres || | ||
| 263 | info->var.xres_virtual != var->xres_virtual || | ||
| 264 | info->var.yres_virtual != var->yres_virtual) { | ||
| 265 | pr_debug("%s: Resolution not supported: X%u x Y%u \n", | ||
| 266 | __FUNCTION__, var->xres, var->yres); | ||
| 267 | return -EINVAL; | ||
| 268 | } | ||
| 269 | |||
| 270 | /* | ||
| 271 | * Memory limit | ||
| 272 | */ | ||
| 273 | |||
| 274 | if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { | ||
| 275 | pr_debug("%s: Memory Limit requested yres_virtual = %u\n", | ||
| 276 | __FUNCTION__, var->yres_virtual); | ||
| 277 | return -ENOMEM; | ||
| 278 | } | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static int bfin_t350mcqb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
| 284 | { | ||
| 285 | struct bfin_t350mcqbfb_info *fbi = info->par; | ||
| 286 | |||
| 287 | if (fbi->lq043_mmap) | ||
| 288 | return -1; | ||
| 289 | |||
| 290 | spin_lock(&fbi->lock); | ||
| 291 | fbi->lq043_mmap = 1; | ||
| 292 | spin_unlock(&fbi->lock); | ||
| 293 | |||
| 294 | vma->vm_start = (unsigned long)(fbi->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET); | ||
| 295 | |||
| 296 | vma->vm_end = vma->vm_start + info->fix.smem_len; | ||
| 297 | /* For those who don't understand how mmap works, go read | ||
| 298 | * Documentation/nommu-mmap.txt. | ||
| 299 | * For those that do, you will know that the VM_MAYSHARE flag | ||
| 300 | * must be set in the vma->vm_flags structure on noMMU | ||
| 301 | * Other flags can be set, and are documented in | ||
| 302 | * include/linux/mm.h | ||
| 303 | */ | ||
| 304 | vma->vm_flags |= VM_MAYSHARE; | ||
| 305 | |||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | |||
| 309 | int bfin_t350mcqb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
| 310 | { | ||
| 311 | if (nocursor) | ||
| 312 | return 0; | ||
| 313 | else | ||
| 314 | return -EINVAL; /* just to force soft_cursor() call */ | ||
| 315 | } | ||
| 316 | |||
| 317 | static int bfin_t350mcqb_fb_setcolreg(u_int regno, u_int red, u_int green, | ||
| 318 | u_int blue, u_int transp, | ||
| 319 | struct fb_info *info) | ||
| 320 | { | ||
| 321 | if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) | ||
| 322 | return -EINVAL; | ||
| 323 | |||
| 324 | if (info->var.grayscale) { | ||
| 325 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
| 326 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
| 327 | } | ||
| 328 | |||
| 329 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
| 330 | |||
| 331 | u32 value; | ||
| 332 | /* Place color in the pseudopalette */ | ||
| 333 | if (regno > 16) | ||
| 334 | return -EINVAL; | ||
| 335 | |||
| 336 | red >>= (16 - info->var.red.length); | ||
| 337 | green >>= (16 - info->var.green.length); | ||
| 338 | blue >>= (16 - info->var.blue.length); | ||
| 339 | |||
| 340 | value = (red << info->var.red.offset) | | ||
| 341 | (green << info->var.green.offset) | | ||
| 342 | (blue << info->var.blue.offset); | ||
| 343 | value &= 0xFFFFFF; | ||
| 344 | |||
| 345 | ((u32 *) (info->pseudo_palette))[regno] = value; | ||
| 346 | |||
| 347 | } | ||
| 348 | |||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | static struct fb_ops bfin_t350mcqb_fb_ops = { | ||
| 353 | .owner = THIS_MODULE, | ||
| 354 | .fb_open = bfin_t350mcqb_fb_open, | ||
| 355 | .fb_release = bfin_t350mcqb_fb_release, | ||
| 356 | .fb_check_var = bfin_t350mcqb_fb_check_var, | ||
| 357 | .fb_fillrect = cfb_fillrect, | ||
| 358 | .fb_copyarea = cfb_copyarea, | ||
| 359 | .fb_imageblit = cfb_imageblit, | ||
| 360 | .fb_mmap = bfin_t350mcqb_fb_mmap, | ||
| 361 | .fb_cursor = bfin_t350mcqb_fb_cursor, | ||
| 362 | .fb_setcolreg = bfin_t350mcqb_fb_setcolreg, | ||
| 363 | }; | ||
| 364 | |||
| 365 | #ifndef NO_BL_SUPPORT | ||
| 366 | static int bl_get_brightness(struct backlight_device *bd) | ||
| 367 | { | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | static struct backlight_ops bfin_lq043fb_bl_ops = { | ||
| 372 | .get_brightness = bl_get_brightness, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static struct backlight_device *bl_dev; | ||
| 376 | |||
| 377 | static int bfin_lcd_get_power(struct lcd_device *dev) | ||
| 378 | { | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | static int bfin_lcd_set_power(struct lcd_device *dev, int power) | ||
| 383 | { | ||
| 384 | return 0; | ||
| 385 | } | ||
| 386 | |||
| 387 | static int bfin_lcd_get_contrast(struct lcd_device *dev) | ||
| 388 | { | ||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast) | ||
| 393 | { | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | static int bfin_lcd_check_fb(struct fb_info *fi) | ||
| 399 | { | ||
| 400 | if (!fi || (fi == &bfin_t350mcqb_fb)) | ||
| 401 | return 1; | ||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | static struct lcd_ops bfin_lcd_ops = { | ||
| 406 | .get_power = bfin_lcd_get_power, | ||
| 407 | .set_power = bfin_lcd_set_power, | ||
| 408 | .get_contrast = bfin_lcd_get_contrast, | ||
| 409 | .set_contrast = bfin_lcd_set_contrast, | ||
| 410 | .check_fb = bfin_lcd_check_fb, | ||
| 411 | }; | ||
| 412 | |||
| 413 | static struct lcd_device *lcd_dev; | ||
| 414 | #endif | ||
| 415 | |||
| 416 | static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id) | ||
| 417 | { | ||
| 418 | /*struct bfin_t350mcqbfb_info *info = (struct bfin_t350mcqbfb_info *)dev_id;*/ | ||
| 419 | |||
| 420 | u16 status = bfin_read_PPI_STATUS(); | ||
| 421 | bfin_write_PPI_STATUS(0xFFFF); | ||
| 422 | |||
| 423 | if (status) { | ||
| 424 | bfin_t350mcqb_disable_ppi(); | ||
| 425 | disable_dma(CH_PPI); | ||
| 426 | |||
| 427 | /* start dma */ | ||
| 428 | enable_dma(CH_PPI); | ||
| 429 | bfin_t350mcqb_enable_ppi(); | ||
| 430 | bfin_write_PPI_STATUS(0xFFFF); | ||
| 431 | } | ||
| 432 | |||
| 433 | return IRQ_HANDLED; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int __init bfin_t350mcqb_probe(struct platform_device *pdev) | ||
| 437 | { | ||
| 438 | struct bfin_t350mcqbfb_info *info; | ||
| 439 | struct fb_info *fbinfo; | ||
| 440 | int ret; | ||
| 441 | |||
| 442 | printk(KERN_INFO DRIVER_NAME ": %dx%d %d-bit RGB FrameBuffer initializing...\n", | ||
| 443 | LCD_X_RES, LCD_Y_RES, LCD_BPP); | ||
| 444 | |||
| 445 | if (request_dma(CH_PPI, "CH_PPI") < 0) { | ||
| 446 | printk(KERN_ERR DRIVER_NAME | ||
| 447 | ": couldn't request CH_PPI DMA\n"); | ||
| 448 | ret = -EFAULT; | ||
| 449 | goto out1; | ||
| 450 | } | ||
| 451 | |||
| 452 | fbinfo = | ||
| 453 | framebuffer_alloc(sizeof(struct bfin_t350mcqbfb_info), &pdev->dev); | ||
| 454 | if (!fbinfo) { | ||
| 455 | ret = -ENOMEM; | ||
| 456 | goto out2; | ||
| 457 | } | ||
| 458 | |||
| 459 | info = fbinfo->par; | ||
| 460 | info->fb = fbinfo; | ||
| 461 | info->dev = &pdev->dev; | ||
| 462 | |||
| 463 | platform_set_drvdata(pdev, fbinfo); | ||
| 464 | |||
| 465 | strcpy(fbinfo->fix.id, driver_name); | ||
| 466 | |||
| 467 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | ||
| 468 | fbinfo->fix.type_aux = 0; | ||
| 469 | fbinfo->fix.xpanstep = 0; | ||
| 470 | fbinfo->fix.ypanstep = 0; | ||
| 471 | fbinfo->fix.ywrapstep = 0; | ||
| 472 | fbinfo->fix.accel = FB_ACCEL_NONE; | ||
| 473 | fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; | ||
| 474 | |||
| 475 | fbinfo->var.nonstd = 0; | ||
| 476 | fbinfo->var.activate = FB_ACTIVATE_NOW; | ||
| 477 | fbinfo->var.height = -1; | ||
| 478 | fbinfo->var.width = -1; | ||
| 479 | fbinfo->var.accel_flags = 0; | ||
| 480 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; | ||
| 481 | |||
| 482 | fbinfo->var.xres = LCD_X_RES; | ||
| 483 | fbinfo->var.xres_virtual = LCD_X_RES; | ||
| 484 | fbinfo->var.yres = LCD_Y_RES; | ||
| 485 | fbinfo->var.yres_virtual = LCD_Y_RES; | ||
| 486 | fbinfo->var.bits_per_pixel = LCD_BPP; | ||
| 487 | |||
| 488 | fbinfo->var.red.offset = 0; | ||
| 489 | fbinfo->var.green.offset = 8; | ||
| 490 | fbinfo->var.blue.offset = 16; | ||
| 491 | fbinfo->var.transp.offset = 0; | ||
| 492 | fbinfo->var.red.length = 8; | ||
| 493 | fbinfo->var.green.length = 8; | ||
| 494 | fbinfo->var.blue.length = 8; | ||
| 495 | fbinfo->var.transp.length = 0; | ||
| 496 | fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8; | ||
| 497 | |||
| 498 | fbinfo->fix.line_length = fbinfo->var.xres_virtual * | ||
| 499 | fbinfo->var.bits_per_pixel / 8; | ||
| 500 | |||
| 501 | |||
| 502 | fbinfo->fbops = &bfin_t350mcqb_fb_ops; | ||
| 503 | fbinfo->flags = FBINFO_FLAG_DEFAULT; | ||
| 504 | |||
| 505 | info->fb_buffer = | ||
| 506 | dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, | ||
| 507 | GFP_KERNEL); | ||
| 508 | |||
| 509 | if (NULL == info->fb_buffer) { | ||
| 510 | printk(KERN_ERR DRIVER_NAME | ||
| 511 | ": couldn't allocate dma buffer.\n"); | ||
| 512 | ret = -ENOMEM; | ||
| 513 | goto out3; | ||
| 514 | } | ||
| 515 | |||
| 516 | memset(info->fb_buffer, 0, fbinfo->fix.smem_len); | ||
| 517 | |||
| 518 | fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; | ||
| 519 | fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; | ||
| 520 | |||
| 521 | fbinfo->fbops = &bfin_t350mcqb_fb_ops; | ||
| 522 | |||
| 523 | fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | ||
| 524 | if (!fbinfo->pseudo_palette) { | ||
| 525 | printk(KERN_ERR DRIVER_NAME | ||
| 526 | "Fail to allocate pseudo_palette\n"); | ||
| 527 | |||
| 528 | ret = -ENOMEM; | ||
| 529 | goto out4; | ||
| 530 | } | ||
| 531 | |||
| 532 | memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); | ||
| 533 | |||
| 534 | if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) | ||
| 535 | < 0) { | ||
| 536 | printk(KERN_ERR DRIVER_NAME | ||
| 537 | "Fail to allocate colormap (%d entries)\n", | ||
| 538 | BFIN_LCD_NBR_PALETTE_ENTRIES); | ||
| 539 | ret = -EFAULT; | ||
| 540 | goto out5; | ||
| 541 | } | ||
| 542 | |||
| 543 | if (bfin_t350mcqb_request_ports(1)) { | ||
| 544 | printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n"); | ||
| 545 | ret = -EFAULT; | ||
| 546 | goto out6; | ||
| 547 | } | ||
| 548 | |||
| 549 | info->irq = platform_get_irq(pdev, 0); | ||
| 550 | if (info->irq < 0) { | ||
| 551 | ret = -EINVAL; | ||
| 552 | goto out7; | ||
| 553 | } | ||
| 554 | |||
| 555 | if (request_irq(info->irq, (void *)bfin_t350mcqb_irq_error, IRQF_DISABLED, | ||
| 556 | "PPI ERROR", info) < 0) { | ||
| 557 | printk(KERN_ERR DRIVER_NAME | ||
| 558 | ": unable to request PPI ERROR IRQ\n"); | ||
| 559 | ret = -EFAULT; | ||
| 560 | goto out7; | ||
| 561 | } | ||
| 562 | |||
| 563 | if (register_framebuffer(fbinfo) < 0) { | ||
| 564 | printk(KERN_ERR DRIVER_NAME | ||
| 565 | ": unable to register framebuffer.\n"); | ||
| 566 | ret = -EINVAL; | ||
| 567 | goto out8; | ||
| 568 | } | ||
| 569 | #ifndef NO_BL_SUPPORT | ||
| 570 | bl_dev = | ||
| 571 | backlight_device_register("bf52x-bl", NULL, NULL, | ||
| 572 | &bfin_lq043fb_bl_ops); | ||
| 573 | bl_dev->props.max_brightness = 255; | ||
| 574 | |||
| 575 | lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); | ||
| 576 | lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); | ||
| 577 | #endif | ||
| 578 | |||
| 579 | return 0; | ||
| 580 | |||
| 581 | out8: | ||
| 582 | free_irq(info->irq, info); | ||
| 583 | out7: | ||
| 584 | bfin_t350mcqb_request_ports(0); | ||
| 585 | out6: | ||
| 586 | fb_dealloc_cmap(&fbinfo->cmap); | ||
| 587 | out5: | ||
| 588 | kfree(fbinfo->pseudo_palette); | ||
| 589 | out4: | ||
| 590 | dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, | ||
| 591 | info->dma_handle); | ||
| 592 | out3: | ||
| 593 | framebuffer_release(fbinfo); | ||
| 594 | out2: | ||
| 595 | free_dma(CH_PPI); | ||
| 596 | out1: | ||
| 597 | platform_set_drvdata(pdev, NULL); | ||
| 598 | |||
| 599 | return ret; | ||
| 600 | } | ||
| 601 | |||
| 602 | static int bfin_t350mcqb_remove(struct platform_device *pdev) | ||
| 603 | { | ||
| 604 | |||
| 605 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
| 606 | struct bfin_t350mcqbfb_info *info = fbinfo->par; | ||
| 607 | |||
| 608 | free_dma(CH_PPI); | ||
| 609 | free_irq(info->irq, info); | ||
| 610 | |||
| 611 | if (info->fb_buffer != NULL) | ||
| 612 | dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, | ||
| 613 | info->dma_handle); | ||
| 614 | |||
| 615 | kfree(fbinfo->pseudo_palette); | ||
| 616 | fb_dealloc_cmap(&fbinfo->cmap); | ||
| 617 | |||
| 618 | #ifndef NO_BL_SUPPORT | ||
| 619 | lcd_device_unregister(lcd_dev); | ||
| 620 | backlight_device_unregister(bl_dev); | ||
| 621 | #endif | ||
| 622 | |||
| 623 | unregister_framebuffer(fbinfo); | ||
| 624 | |||
| 625 | bfin_t350mcqb_request_ports(0); | ||
| 626 | |||
| 627 | printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n"); | ||
| 628 | |||
| 629 | return 0; | ||
| 630 | } | ||
| 631 | |||
| 632 | #ifdef CONFIG_PM | ||
| 633 | static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 634 | { | ||
| 635 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
| 636 | struct bfin_t350mcqbfb_info *info = fbinfo->par; | ||
| 637 | |||
| 638 | bfin_t350mcqb_disable_ppi(); | ||
| 639 | disable_dma(CH_PPI); | ||
| 640 | bfin_write_PPI_STATUS(0xFFFF); | ||
| 641 | |||
| 642 | return 0; | ||
| 643 | } | ||
| 644 | |||
| 645 | static int bfin_t350mcqb_resume(struct platform_device *pdev) | ||
| 646 | { | ||
| 647 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
| 648 | struct bfin_t350mcqbfb_info *info = fbinfo->par; | ||
| 649 | |||
| 650 | enable_dma(CH_PPI); | ||
| 651 | bfin_t350mcqb_enable_ppi(); | ||
| 652 | |||
| 653 | return 0; | ||
| 654 | } | ||
| 655 | #else | ||
| 656 | #define bfin_t350mcqb_suspend NULL | ||
| 657 | #define bfin_t350mcqb_resume NULL | ||
| 658 | #endif | ||
| 659 | |||
| 660 | static struct platform_driver bfin_t350mcqb_driver = { | ||
| 661 | .probe = bfin_t350mcqb_probe, | ||
| 662 | .remove = bfin_t350mcqb_remove, | ||
| 663 | .suspend = bfin_t350mcqb_suspend, | ||
| 664 | .resume = bfin_t350mcqb_resume, | ||
| 665 | .driver = { | ||
| 666 | .name = DRIVER_NAME, | ||
| 667 | .owner = THIS_MODULE, | ||
| 668 | }, | ||
| 669 | }; | ||
| 670 | |||
| 671 | static int __devinit bfin_t350mcqb_driver_init(void) | ||
| 672 | { | ||
| 673 | return platform_driver_register(&bfin_t350mcqb_driver); | ||
| 674 | } | ||
| 675 | |||
| 676 | static void __exit bfin_t350mcqb_driver_cleanup(void) | ||
| 677 | { | ||
| 678 | platform_driver_unregister(&bfin_t350mcqb_driver); | ||
| 679 | } | ||
| 680 | |||
| 681 | MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); | ||
| 682 | MODULE_LICENSE("GPL"); | ||
| 683 | |||
| 684 | module_init(bfin_t350mcqb_driver_init); | ||
| 685 | module_exit(bfin_t350mcqb_driver_cleanup); | ||
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 80cd117ca65c..01f77bcc68f9 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c | |||
| @@ -889,7 +889,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev) | |||
| 889 | struct mbxfb_info *mfbi; | 889 | struct mbxfb_info *mfbi; |
| 890 | struct mbxfb_platform_data *pdata; | 890 | struct mbxfb_platform_data *pdata; |
| 891 | 891 | ||
| 892 | dev_dbg(dev, "mbxfb_probe\n"); | 892 | dev_dbg(&dev->dev, "mbxfb_probe\n"); |
| 893 | 893 | ||
| 894 | pdata = dev->dev.platform_data; | 894 | pdata = dev->dev.platform_data; |
| 895 | if (!pdata) { | 895 | if (!pdata) { |
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index e7c8db2eb49b..f98be301140c 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c | |||
| @@ -505,16 +505,24 @@ ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber) | |||
| 505 | static void | 505 | static void |
| 506 | rattlerSetupPlanes(struct stifb_info *fb) | 506 | rattlerSetupPlanes(struct stifb_info *fb) |
| 507 | { | 507 | { |
| 508 | int saved_id, y; | ||
| 509 | |||
| 510 | /* Write RAMDAC pixel read mask register so all overlay | ||
| 511 | * planes are display-enabled. (CRX24 uses Bt462 pixel | ||
| 512 | * read mask register for overlay planes, not image planes). | ||
| 513 | */ | ||
| 508 | CRX24_SETUP_RAMDAC(fb); | 514 | CRX24_SETUP_RAMDAC(fb); |
| 509 | 515 | ||
| 510 | /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */ | 516 | /* change fb->id temporarily to fool SETUP_FB() */ |
| 511 | WRITE_WORD(0x83000300, fb, REG_14); | 517 | saved_id = fb->id; |
| 512 | SETUP_HW(fb); | 518 | fb->id = CRX24_OVERLAY_PLANES; |
| 513 | WRITE_BYTE(1, fb, REG_16b1); | 519 | SETUP_FB(fb); |
| 520 | fb->id = saved_id; | ||
| 521 | |||
| 522 | for (y = 0; y < fb->info.var.yres; ++y) | ||
| 523 | memset(fb->info.screen_base + y * fb->info.fix.line_length, | ||
| 524 | 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8); | ||
| 514 | 525 | ||
| 515 | fb_memset((void*)fb->info.fix.smem_start, 0xff, | ||
| 516 | fb->info.var.yres*fb->info.fix.line_length); | ||
| 517 | |||
| 518 | CRX24_SET_OVLY_MASK(fb); | 526 | CRX24_SET_OVLY_MASK(fb); |
| 519 | SETUP_FB(fb); | 527 | SETUP_FB(fb); |
| 520 | } | 528 | } |
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 919ce75db9e2..0a4e07d43d2d 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c | |||
| @@ -566,44 +566,32 @@ static inline void write3CE(int reg, unsigned char val) | |||
| 566 | 566 | ||
| 567 | static void enable_mmio(void) | 567 | static void enable_mmio(void) |
| 568 | { | 568 | { |
| 569 | unsigned char tmp; | ||
| 570 | |||
| 571 | /* Goto New Mode */ | 569 | /* Goto New Mode */ |
| 572 | outb(0x0B, 0x3C4); | 570 | outb(0x0B, 0x3C4); |
| 573 | inb(0x3C5); | 571 | inb(0x3C5); |
| 574 | 572 | ||
| 575 | /* Unprotect registers */ | 573 | /* Unprotect registers */ |
| 576 | outb(NewMode1, 0x3C4); | 574 | outb(NewMode1, 0x3C4); |
| 577 | tmp = inb(0x3C5); | ||
| 578 | outb(0x80, 0x3C5); | 575 | outb(0x80, 0x3C5); |
| 579 | 576 | ||
| 580 | /* Enable MMIO */ | 577 | /* Enable MMIO */ |
| 581 | outb(PCIReg, 0x3D4); | 578 | outb(PCIReg, 0x3D4); |
| 582 | outb(inb(0x3D5) | 0x01, 0x3D5); | 579 | outb(inb(0x3D5) | 0x01, 0x3D5); |
| 583 | |||
| 584 | t_outb(NewMode1, 0x3C4); | ||
| 585 | t_outb(tmp, 0x3C5); | ||
| 586 | } | 580 | } |
| 587 | 581 | ||
| 588 | static void disable_mmio(void) | 582 | static void disable_mmio(void) |
| 589 | { | 583 | { |
| 590 | unsigned char tmp; | ||
| 591 | |||
| 592 | /* Goto New Mode */ | 584 | /* Goto New Mode */ |
| 593 | t_outb(0x0B, 0x3C4); | 585 | t_outb(0x0B, 0x3C4); |
| 594 | t_inb(0x3C5); | 586 | t_inb(0x3C5); |
| 595 | 587 | ||
| 596 | /* Unprotect registers */ | 588 | /* Unprotect registers */ |
| 597 | t_outb(NewMode1, 0x3C4); | 589 | t_outb(NewMode1, 0x3C4); |
| 598 | tmp = t_inb(0x3C5); | ||
| 599 | t_outb(0x80, 0x3C5); | 590 | t_outb(0x80, 0x3C5); |
| 600 | 591 | ||
| 601 | /* Disable MMIO */ | 592 | /* Disable MMIO */ |
| 602 | t_outb(PCIReg, 0x3D4); | 593 | t_outb(PCIReg, 0x3D4); |
| 603 | t_outb(t_inb(0x3D5) & ~0x01, 0x3D5); | 594 | t_outb(t_inb(0x3D5) & ~0x01, 0x3D5); |
| 604 | |||
| 605 | outb(NewMode1, 0x3C4); | ||
| 606 | outb(tmp, 0x3C5); | ||
| 607 | } | 595 | } |
| 608 | 596 | ||
| 609 | #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) | 597 | #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) |
| @@ -757,7 +745,7 @@ static unsigned int __devinit get_memsize(void) | |||
| 757 | switch (tmp) { | 745 | switch (tmp) { |
| 758 | 746 | ||
| 759 | case 0x01: | 747 | case 0x01: |
| 760 | k = 512; | 748 | k = 512 * Kb; |
| 761 | break; | 749 | break; |
| 762 | case 0x02: | 750 | case 0x02: |
| 763 | k = 6 * Mb; /* XP */ | 751 | k = 6 * Mb; /* XP */ |
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c index 5941ca601a3a..df72f90123df 100644 --- a/drivers/watchdog/cpu5wdt.c +++ b/drivers/watchdog/cpu5wdt.c | |||
| @@ -59,9 +59,9 @@ static int ticks = 10000; | |||
| 59 | 59 | ||
| 60 | static struct { | 60 | static struct { |
| 61 | struct completion stop; | 61 | struct completion stop; |
| 62 | volatile int running; | 62 | int running; |
| 63 | struct timer_list timer; | 63 | struct timer_list timer; |
| 64 | volatile int queue; | 64 | int queue; |
| 65 | int default_ticks; | 65 | int default_ticks; |
| 66 | unsigned long inuse; | 66 | unsigned long inuse; |
| 67 | } cpu5wdt_device; | 67 | } cpu5wdt_device; |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index a2e174b09fe7..6483d1066b95 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
| @@ -58,41 +58,6 @@ struct bios32_service_dir { | |||
| 58 | u8 reserved[5]; | 58 | u8 reserved[5]; |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | /* | ||
| 62 | * smbios_entry_point - defines SMBIOS entry point structure | ||
| 63 | * | ||
| 64 | * anchor[4] - anchor string (_SM_) | ||
| 65 | * checksum - checksum of the entry point structure | ||
| 66 | * length - length of the entry point structure | ||
| 67 | * major_ver - major version (02h for revision 2.1) | ||
| 68 | * minor_ver - minor version (01h for revision 2.1) | ||
| 69 | * max_struct_size - size of the largest SMBIOS structure | ||
| 70 | * revision - entry point structure revision implemented | ||
| 71 | * formatted_area[5] - reserved | ||
| 72 | * intermediate_anchor[5] - intermediate anchor string (_DMI_) | ||
| 73 | * intermediate_checksum - intermediate checksum | ||
| 74 | * table_length - structure table length | ||
| 75 | * table_address - structure table address | ||
| 76 | * table_num_structs - number of SMBIOS structures present | ||
| 77 | * bcd_revision - BCD revision | ||
| 78 | */ | ||
| 79 | struct smbios_entry_point { | ||
| 80 | u8 anchor[4]; | ||
| 81 | u8 checksum; | ||
| 82 | u8 length; | ||
| 83 | u8 major_ver; | ||
| 84 | u8 minor_ver; | ||
| 85 | u16 max_struct_size; | ||
| 86 | u8 revision; | ||
| 87 | u8 formatted_area[5]; | ||
| 88 | u8 intermediate_anchor[5]; | ||
| 89 | u8 intermediate_checksum; | ||
| 90 | u16 table_length; | ||
| 91 | u64 table_address; | ||
| 92 | u16 table_num_structs; | ||
| 93 | u8 bcd_revision; | ||
| 94 | }; | ||
| 95 | |||
| 96 | /* type 212 */ | 61 | /* type 212 */ |
| 97 | struct smbios_cru64_info { | 62 | struct smbios_cru64_info { |
| 98 | u8 type; | 63 | u8 type; |
| @@ -175,31 +140,13 @@ static struct pci_device_id hpwdt_devices[] = { | |||
| 175 | }; | 140 | }; |
| 176 | MODULE_DEVICE_TABLE(pci, hpwdt_devices); | 141 | MODULE_DEVICE_TABLE(pci, hpwdt_devices); |
| 177 | 142 | ||
| 178 | /* | ||
| 179 | * bios_checksum | ||
| 180 | */ | ||
| 181 | static int __devinit bios_checksum(const char __iomem *ptr, int len) | ||
| 182 | { | ||
| 183 | char sum = 0; | ||
| 184 | int i; | ||
| 185 | |||
| 186 | /* | ||
| 187 | * calculate checksum of size bytes. This should add up | ||
| 188 | * to zero if we have a valid header. | ||
| 189 | */ | ||
| 190 | for (i = 0; i < len; i++) | ||
| 191 | sum += ptr[i]; | ||
| 192 | |||
| 193 | return ((sum == 0) && (len > 0)); | ||
| 194 | } | ||
| 195 | |||
| 196 | #ifndef CONFIG_X86_64 | 143 | #ifndef CONFIG_X86_64 |
| 197 | /* --32 Bit Bios------------------------------------------------------------ */ | 144 | /* --32 Bit Bios------------------------------------------------------------ */ |
| 198 | 145 | ||
| 199 | #define HPWDT_ARCH 32 | 146 | #define HPWDT_ARCH 32 |
| 200 | 147 | ||
| 201 | asmlinkage void asminline_call(struct cmn_registers *pi86Regs, | 148 | static void asminline_call(struct cmn_registers *pi86Regs, |
| 202 | unsigned long *pRomEntry) | 149 | unsigned long *pRomEntry) |
| 203 | { | 150 | { |
| 204 | asm("pushl %ebp \n\t" | 151 | asm("pushl %ebp \n\t" |
| 205 | "movl %esp, %ebp \n\t" | 152 | "movl %esp, %ebp \n\t" |
| @@ -303,6 +250,24 @@ static int __devinit cru_detect(unsigned long map_entry, | |||
| 303 | } | 250 | } |
| 304 | 251 | ||
| 305 | /* | 252 | /* |
| 253 | * bios_checksum | ||
| 254 | */ | ||
| 255 | static int __devinit bios_checksum(const char __iomem *ptr, int len) | ||
| 256 | { | ||
| 257 | char sum = 0; | ||
| 258 | int i; | ||
| 259 | |||
| 260 | /* | ||
| 261 | * calculate checksum of size bytes. This should add up | ||
| 262 | * to zero if we have a valid header. | ||
| 263 | */ | ||
| 264 | for (i = 0; i < len; i++) | ||
| 265 | sum += ptr[i]; | ||
| 266 | |||
| 267 | return ((sum == 0) && (len > 0)); | ||
| 268 | } | ||
| 269 | |||
| 270 | /* | ||
| 306 | * bios32_present | 271 | * bios32_present |
| 307 | * | 272 | * |
| 308 | * Routine Description: | 273 | * Routine Description: |
| @@ -368,8 +333,8 @@ static int __devinit detect_cru_service(void) | |||
| 368 | 333 | ||
| 369 | #define HPWDT_ARCH 64 | 334 | #define HPWDT_ARCH 64 |
| 370 | 335 | ||
| 371 | asmlinkage void asminline_call(struct cmn_registers *pi86Regs, | 336 | static void asminline_call(struct cmn_registers *pi86Regs, |
| 372 | unsigned long *pRomEntry) | 337 | unsigned long *pRomEntry) |
| 373 | { | 338 | { |
| 374 | asm("pushq %rbp \n\t" | 339 | asm("pushq %rbp \n\t" |
| 375 | "movq %rsp, %rbp \n\t" | 340 | "movq %rsp, %rbp \n\t" |
| @@ -410,12 +375,8 @@ asmlinkage void asminline_call(struct cmn_registers *pi86Regs, | |||
| 410 | * dmi_find_cru | 375 | * dmi_find_cru |
| 411 | * | 376 | * |
| 412 | * Routine Description: | 377 | * Routine Description: |
| 413 | * This function checks wether or not a SMBIOS/DMI record is | 378 | * This function checks whether or not a SMBIOS/DMI record is |
| 414 | * the 64bit CRU info or not | 379 | * the 64bit CRU info or not |
| 415 | * | ||
| 416 | * Return Value: | ||
| 417 | * 0 : SUCCESS - if record found | ||
| 418 | * <0 : FAILURE - if record not found | ||
| 419 | */ | 380 | */ |
| 420 | static void __devinit dmi_find_cru(const struct dmi_header *dm) | 381 | static void __devinit dmi_find_cru(const struct dmi_header *dm) |
| 421 | { | 382 | { |
| @@ -434,138 +395,11 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm) | |||
| 434 | } | 395 | } |
| 435 | } | 396 | } |
| 436 | 397 | ||
| 437 | /* | ||
| 438 | * dmi_table | ||
| 439 | * | ||
| 440 | * Routine Description: | ||
| 441 | * Decode the SMBIOS/DMI table and check if we have a 64bit CRU record | ||
| 442 | * or not. | ||
| 443 | * | ||
| 444 | * We have to be cautious here. We have seen BIOSes with DMI pointers | ||
| 445 | * pointing to completely the wrong place for example | ||
| 446 | */ | ||
| 447 | static void __devinit dmi_table(u8 *buf, int len, int num, | ||
| 448 | void (*decode)(const struct dmi_header *)) | ||
| 449 | { | ||
| 450 | u8 *data = buf; | ||
| 451 | int i = 0; | ||
| 452 | |||
| 453 | /* | ||
| 454 | * Stop when we see all the items the table claimed to have | ||
| 455 | * OR we run off the end of the table (also happens) | ||
| 456 | */ | ||
| 457 | while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { | ||
| 458 | const struct dmi_header *dm = (const struct dmi_header *)data; | ||
| 459 | |||
| 460 | /* | ||
| 461 | * We want to know the total length (formated area and strings) | ||
| 462 | * before decoding to make sure we won't run off the table in | ||
| 463 | * dmi_decode or dmi_string | ||
| 464 | */ | ||
| 465 | data += dm->length; | ||
| 466 | while ((data - buf < len - 1) && (data[0] || data[1])) | ||
| 467 | data++; | ||
| 468 | if (data - buf < len - 1) | ||
| 469 | decode(dm); | ||
| 470 | data += 2; | ||
| 471 | i++; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | /* | ||
| 476 | * smbios_present | ||
| 477 | * | ||
| 478 | * Routine Description: | ||
| 479 | * This function parses the SMBIOS entry point table to retrieve | ||
| 480 | * the 64 bit CRU Service. | ||
| 481 | * | ||
| 482 | * Return Value: | ||
| 483 | * 0 : SUCCESS | ||
| 484 | * <0 : FAILURE | ||
| 485 | */ | ||
| 486 | static int __devinit smbios_present(const char __iomem *p) | ||
| 487 | { | ||
| 488 | struct smbios_entry_point *eps = | ||
| 489 | (struct smbios_entry_point *) p; | ||
| 490 | int length; | ||
| 491 | u8 *buf; | ||
| 492 | |||
| 493 | /* check if we have indeed the SMBIOS table entry point */ | ||
| 494 | if ((strncmp((char *)eps->anchor, "_SM_", | ||
| 495 | sizeof(eps->anchor))) == 0) { | ||
| 496 | length = eps->length; | ||
| 497 | |||
| 498 | /* SMBIOS v2.1 implementation might use 0x1e */ | ||
| 499 | if ((length == 0x1e) && | ||
| 500 | (eps->major_ver == 2) && | ||
| 501 | (eps->minor_ver == 1)) | ||
| 502 | length = 0x1f; | ||
| 503 | |||
| 504 | /* | ||
| 505 | * Now we will check: | ||
| 506 | * - SMBIOS checksum must be 0 | ||
| 507 | * - intermediate anchor should be _DMI_ | ||
| 508 | * - intermediate checksum should be 0 | ||
| 509 | */ | ||
| 510 | if ((bios_checksum(p, length)) && | ||
| 511 | (strncmp((char *)eps->intermediate_anchor, "_DMI_", | ||
| 512 | sizeof(eps->intermediate_anchor)) == 0) && | ||
| 513 | (bios_checksum(p+0x10, 15))) { | ||
| 514 | buf = ioremap(eps->table_address, eps->table_length); | ||
| 515 | if (buf == NULL) | ||
| 516 | return -ENODEV; | ||
| 517 | |||
| 518 | |||
| 519 | /* Scan the DMI table for the 64 bit CRU service */ | ||
| 520 | dmi_table(buf, eps->table_length, | ||
| 521 | eps->table_num_structs, dmi_find_cru); | ||
| 522 | |||
| 523 | iounmap(buf); | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 528 | return -ENODEV; | ||
| 529 | } | ||
| 530 | |||
| 531 | static int __devinit smbios_scan_machine(void) | ||
| 532 | { | ||
| 533 | char __iomem *p, *q; | ||
| 534 | int rc; | ||
| 535 | |||
| 536 | if (efi_enabled) { | ||
| 537 | if (efi.smbios == EFI_INVALID_TABLE_ADDR) | ||
| 538 | return -ENODEV; | ||
| 539 | |||
| 540 | p = ioremap(efi.smbios, 32); | ||
| 541 | if (p == NULL) | ||
| 542 | return -ENOMEM; | ||
| 543 | |||
| 544 | rc = smbios_present(p); | ||
| 545 | iounmap(p); | ||
| 546 | } else { | ||
| 547 | /* | ||
| 548 | * Search from 0x0f0000 through 0x0fffff, inclusive. | ||
| 549 | */ | ||
| 550 | p = ioremap(PCI_ROM_BASE1, ROM_SIZE); | ||
| 551 | if (p == NULL) | ||
| 552 | return -ENOMEM; | ||
| 553 | |||
| 554 | for (q = p; q < p + ROM_SIZE; q += 16) { | ||
| 555 | rc = smbios_present(q); | ||
| 556 | if (!rc) { | ||
| 557 | break; | ||
| 558 | } | ||
| 559 | } | ||
| 560 | iounmap(p); | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | static int __devinit detect_cru_service(void) | 398 | static int __devinit detect_cru_service(void) |
| 565 | { | 399 | { |
| 566 | cru_rom_addr = NULL; | 400 | cru_rom_addr = NULL; |
| 567 | 401 | ||
| 568 | smbios_scan_machine(); /* will become dmi_walk(dmi_find_cru); */ | 402 | dmi_walk(dmi_find_cru); |
| 569 | 403 | ||
| 570 | /* if cru_rom_addr has been set then we found a CRU service */ | 404 | /* if cru_rom_addr has been set then we found a CRU service */ |
| 571 | return ((cru_rom_addr != NULL)? 0: -ENODEV); | 405 | return ((cru_rom_addr != NULL)? 0: -ENODEV); |
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index 1b6d7d1b715d..1efcad3b6fca 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c | |||
| @@ -7,7 +7,8 @@ | |||
| 7 | * | 7 | * |
| 8 | * drivers/char/watchdog/scx200_wdt.c | 8 | * drivers/char/watchdog/scx200_wdt.c |
| 9 | * drivers/hwmon/it87.c | 9 | * drivers/hwmon/it87.c |
| 10 | * IT8712F EC-LPC I/O Preliminary Specification 0.9.2.pdf | 10 | * IT8712F EC-LPC I/O Preliminary Specification 0.8.2 |
| 11 | * IT8712F EC-LPC I/O Preliminary Specification 0.9.3 | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License as | 14 | * modify it under the terms of the GNU General Public License as |
| @@ -40,6 +41,7 @@ MODULE_DESCRIPTION("IT8712F Watchdog Driver"); | |||
| 40 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
| 41 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 42 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
| 42 | 43 | ||
| 44 | static int max_units = 255; | ||
| 43 | static int margin = 60; /* in seconds */ | 45 | static int margin = 60; /* in seconds */ |
| 44 | module_param(margin, int, 0); | 46 | module_param(margin, int, 0); |
| 45 | MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); | 47 | MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); |
| @@ -51,6 +53,7 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); | |||
| 51 | static struct semaphore it8712f_wdt_sem; | 53 | static struct semaphore it8712f_wdt_sem; |
| 52 | static unsigned expect_close; | 54 | static unsigned expect_close; |
| 53 | static spinlock_t io_lock; | 55 | static spinlock_t io_lock; |
| 56 | static unsigned char revision; | ||
| 54 | 57 | ||
| 55 | /* Dog Food address - We use the game port address */ | 58 | /* Dog Food address - We use the game port address */ |
| 56 | static unsigned short address; | 59 | static unsigned short address; |
| @@ -108,6 +111,15 @@ superio_inw(int reg) | |||
| 108 | return val; | 111 | return val; |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 114 | static void | ||
| 115 | superio_outw(int val, int reg) | ||
| 116 | { | ||
| 117 | outb(reg++, REG); | ||
| 118 | outb((val >> 8) & 0xff, VAL); | ||
| 119 | outb(reg, REG); | ||
| 120 | outb(val & 0xff, VAL); | ||
| 121 | } | ||
| 122 | |||
| 111 | static inline void | 123 | static inline void |
| 112 | superio_select(int ldn) | 124 | superio_select(int ldn) |
| 113 | { | 125 | { |
| @@ -143,15 +155,33 @@ static void | |||
| 143 | it8712f_wdt_update_margin(void) | 155 | it8712f_wdt_update_margin(void) |
| 144 | { | 156 | { |
| 145 | int config = WDT_OUT_KRST | WDT_OUT_PWROK; | 157 | int config = WDT_OUT_KRST | WDT_OUT_PWROK; |
| 146 | 158 | int units = margin; | |
| 147 | printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); | 159 | |
| 148 | 160 | /* Switch to minutes precision if the configured margin | |
| 149 | /* The timeout register only has 8bits wide */ | 161 | * value does not fit within the register width. |
| 150 | if (margin < 256) | 162 | */ |
| 151 | config |= WDT_UNIT_SEC; /* else UNIT are MINUTES */ | 163 | if (units <= max_units) { |
| 164 | config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */ | ||
| 165 | printk(KERN_INFO NAME ": timer margin %d seconds\n", units); | ||
| 166 | } else { | ||
| 167 | units /= 60; | ||
| 168 | printk(KERN_INFO NAME ": timer margin %d minutes\n", units); | ||
| 169 | } | ||
| 152 | superio_outb(config, WDT_CONFIG); | 170 | superio_outb(config, WDT_CONFIG); |
| 153 | 171 | ||
| 154 | superio_outb((margin > 255) ? (margin / 60) : margin, WDT_TIMEOUT); | 172 | if (revision >= 0x08) |
| 173 | superio_outw(units, WDT_TIMEOUT); | ||
| 174 | else | ||
| 175 | superio_outb(units, WDT_TIMEOUT); | ||
| 176 | } | ||
| 177 | |||
| 178 | static int | ||
| 179 | it8712f_wdt_get_status(void) | ||
| 180 | { | ||
| 181 | if (superio_inb(WDT_CONTROL) & 0x01) | ||
| 182 | return WDIOF_CARDRESET; | ||
| 183 | else | ||
| 184 | return 0; | ||
| 155 | } | 185 | } |
| 156 | 186 | ||
| 157 | static void | 187 | static void |
| @@ -234,7 +264,7 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, | |||
| 234 | .firmware_version = 1, | 264 | .firmware_version = 1, |
| 235 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 265 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
| 236 | }; | 266 | }; |
| 237 | int new_margin; | 267 | int value; |
| 238 | 268 | ||
| 239 | switch (cmd) { | 269 | switch (cmd) { |
| 240 | default: | 270 | default: |
| @@ -244,17 +274,27 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, | |||
| 244 | return -EFAULT; | 274 | return -EFAULT; |
| 245 | return 0; | 275 | return 0; |
| 246 | case WDIOC_GETSTATUS: | 276 | case WDIOC_GETSTATUS: |
| 277 | superio_enter(); | ||
| 278 | superio_select(LDN_GPIO); | ||
| 279 | |||
| 280 | value = it8712f_wdt_get_status(); | ||
| 281 | |||
| 282 | superio_exit(); | ||
| 283 | |||
| 284 | return put_user(value, p); | ||
| 247 | case WDIOC_GETBOOTSTATUS: | 285 | case WDIOC_GETBOOTSTATUS: |
| 248 | return put_user(0, p); | 286 | return put_user(0, p); |
| 249 | case WDIOC_KEEPALIVE: | 287 | case WDIOC_KEEPALIVE: |
| 250 | it8712f_wdt_ping(); | 288 | it8712f_wdt_ping(); |
| 251 | return 0; | 289 | return 0; |
| 252 | case WDIOC_SETTIMEOUT: | 290 | case WDIOC_SETTIMEOUT: |
| 253 | if (get_user(new_margin, p)) | 291 | if (get_user(value, p)) |
| 254 | return -EFAULT; | 292 | return -EFAULT; |
| 255 | if (new_margin < 1) | 293 | if (value < 1) |
| 294 | return -EINVAL; | ||
| 295 | if (value > (max_units * 60)) | ||
| 256 | return -EINVAL; | 296 | return -EINVAL; |
| 257 | margin = new_margin; | 297 | margin = value; |
| 258 | superio_enter(); | 298 | superio_enter(); |
| 259 | superio_select(LDN_GPIO); | 299 | superio_select(LDN_GPIO); |
| 260 | 300 | ||
| @@ -262,6 +302,7 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, | |||
| 262 | 302 | ||
| 263 | superio_exit(); | 303 | superio_exit(); |
| 264 | it8712f_wdt_ping(); | 304 | it8712f_wdt_ping(); |
| 305 | /* Fall through */ | ||
| 265 | case WDIOC_GETTIMEOUT: | 306 | case WDIOC_GETTIMEOUT: |
| 266 | if (put_user(margin, p)) | 307 | if (put_user(margin, p)) |
| 267 | return -EFAULT; | 308 | return -EFAULT; |
| @@ -336,9 +377,18 @@ it8712f_wdt_find(unsigned short *address) | |||
| 336 | } | 377 | } |
| 337 | 378 | ||
| 338 | err = 0; | 379 | err = 0; |
| 339 | printk(KERN_DEBUG NAME ": Found IT%04xF chip revision %d - " | 380 | revision = superio_inb(DEVREV) & 0x0f; |
| 381 | |||
| 382 | /* Later revisions have 16-bit values per datasheet 0.9.1 */ | ||
| 383 | if (revision >= 0x08) | ||
| 384 | max_units = 65535; | ||
| 385 | |||
| 386 | if (margin > (max_units * 60)) | ||
| 387 | margin = (max_units * 60); | ||
| 388 | |||
| 389 | printk(KERN_INFO NAME ": Found IT%04xF chip revision %d - " | ||
| 340 | "using DogFood address 0x%x\n", | 390 | "using DogFood address 0x%x\n", |
| 341 | chip_type, superio_inb(DEVREV) & 0x0f, *address); | 391 | chip_type, revision, *address); |
| 342 | 392 | ||
| 343 | exit: | 393 | exit: |
| 344 | superio_exit(); | 394 | superio_exit(); |
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c index e6e07b4575eb..6905135a776c 100644 --- a/drivers/watchdog/machzwd.c +++ b/drivers/watchdog/machzwd.c | |||
| @@ -141,7 +141,7 @@ static unsigned long next_heartbeat = 0; | |||
| 141 | #ifndef ZF_DEBUG | 141 | #ifndef ZF_DEBUG |
| 142 | # define dprintk(format, args...) | 142 | # define dprintk(format, args...) |
| 143 | #else | 143 | #else |
| 144 | # define dprintk(format, args...) printk(KERN_DEBUG PFX ":%s:%d: " format, __FUNCTION__, __LINE__ , ## args) | 144 | # define dprintk(format, args...) printk(KERN_DEBUG PFX ":%s:%d: " format, __func__, __LINE__ , ## args) |
| 145 | #endif | 145 | #endif |
| 146 | 146 | ||
| 147 | 147 | ||
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index 789831b3fa00..10b89f2703bd 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c | |||
| @@ -59,9 +59,9 @@ static int ticks = 100 * HZ; | |||
| 59 | 59 | ||
| 60 | static struct { | 60 | static struct { |
| 61 | struct completion stop; | 61 | struct completion stop; |
| 62 | volatile int running; | 62 | int running; |
| 63 | struct timer_list timer; | 63 | struct timer_list timer; |
| 64 | volatile int queue; | 64 | int queue; |
| 65 | int default_ticks; | 65 | int default_ticks; |
| 66 | unsigned long inuse; | 66 | unsigned long inuse; |
| 67 | unsigned gpio; | 67 | unsigned gpio; |
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index 0f3fd6c9c354..bf443d077a1e 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c | |||
| @@ -179,11 +179,11 @@ static void usb_pcwd_intr_done(struct urb *urb) | |||
| 179 | case -ENOENT: | 179 | case -ENOENT: |
| 180 | case -ESHUTDOWN: | 180 | case -ESHUTDOWN: |
| 181 | /* this urb is terminated, clean up */ | 181 | /* this urb is terminated, clean up */ |
| 182 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | 182 | dbg("%s - urb shutting down with status: %d", __func__, urb->status); |
| 183 | return; | 183 | return; |
| 184 | /* -EPIPE: should clear the halt */ | 184 | /* -EPIPE: should clear the halt */ |
| 185 | default: /* error */ | 185 | default: /* error */ |
| 186 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | 186 | dbg("%s - nonzero urb status received: %d", __func__, urb->status); |
| 187 | goto resubmit; | 187 | goto resubmit; |
| 188 | } | 188 | } |
| 189 | 189 | ||
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 5d1c15f83d23..7645e8812156 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
| @@ -144,7 +144,7 @@ static int s3c2410wdt_start(void) | |||
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n", | 146 | DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n", |
| 147 | __FUNCTION__, wdt_count, wtcon); | 147 | __func__, wdt_count, wtcon); |
| 148 | 148 | ||
| 149 | writel(wdt_count, wdt_base + S3C2410_WTDAT); | 149 | writel(wdt_count, wdt_base + S3C2410_WTDAT); |
| 150 | writel(wdt_count, wdt_base + S3C2410_WTCNT); | 150 | writel(wdt_count, wdt_base + S3C2410_WTCNT); |
| @@ -167,7 +167,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) | |||
| 167 | count = timeout * freq; | 167 | count = timeout * freq; |
| 168 | 168 | ||
| 169 | DBG("%s: count=%d, timeout=%d, freq=%d\n", | 169 | DBG("%s: count=%d, timeout=%d, freq=%d\n", |
| 170 | __FUNCTION__, count, timeout, freq); | 170 | __func__, count, timeout, freq); |
| 171 | 171 | ||
| 172 | /* if the count is bigger than the watchdog register, | 172 | /* if the count is bigger than the watchdog register, |
| 173 | then work out what we need to do (and if) we can | 173 | then work out what we need to do (and if) we can |
| @@ -189,7 +189,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) | |||
| 189 | tmr_margin = timeout; | 189 | tmr_margin = timeout; |
| 190 | 190 | ||
| 191 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", | 191 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", |
| 192 | __FUNCTION__, timeout, divisor, count, count/divisor); | 192 | __func__, timeout, divisor, count, count/divisor); |
| 193 | 193 | ||
| 194 | count /= divisor; | 194 | count /= divisor; |
| 195 | wdt_count = count; | 195 | wdt_count = count; |
| @@ -355,7 +355,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 355 | int ret; | 355 | int ret; |
| 356 | int size; | 356 | int size; |
| 357 | 357 | ||
| 358 | DBG("%s: probe=%p\n", __FUNCTION__, pdev); | 358 | DBG("%s: probe=%p\n", __func__, pdev); |
| 359 | 359 | ||
| 360 | dev = &pdev->dev; | 360 | dev = &pdev->dev; |
| 361 | wdt_dev = &pdev->dev; | 361 | wdt_dev = &pdev->dev; |
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 61dde863bd40..1277f7e9cc54 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c | |||
| @@ -298,7 +298,7 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 298 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, | 298 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, |
| 299 | PAGE_SIZE, vma->vm_page_prot)) { | 299 | PAGE_SIZE, vma->vm_page_prot)) { |
| 300 | printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", | 300 | printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", |
| 301 | __FUNCTION__); | 301 | __func__); |
| 302 | return -EAGAIN; | 302 | return -EAGAIN; |
| 303 | } | 303 | } |
| 304 | 304 | ||
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index ee50c9610e7f..b8057c51b205 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
| @@ -451,9 +451,9 @@ static void o2net_set_nn_state(struct o2net_node *nn, | |||
| 451 | /* delay if we're withing a RECONNECT_DELAY of the | 451 | /* delay if we're withing a RECONNECT_DELAY of the |
| 452 | * last attempt */ | 452 | * last attempt */ |
| 453 | delay = (nn->nn_last_connect_attempt + | 453 | delay = (nn->nn_last_connect_attempt + |
| 454 | msecs_to_jiffies(o2net_reconnect_delay(sc->sc_node))) | 454 | msecs_to_jiffies(o2net_reconnect_delay(NULL))) |
| 455 | - jiffies; | 455 | - jiffies; |
| 456 | if (delay > msecs_to_jiffies(o2net_reconnect_delay(sc->sc_node))) | 456 | if (delay > msecs_to_jiffies(o2net_reconnect_delay(NULL))) |
| 457 | delay = 0; | 457 | delay = 0; |
| 458 | mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay); | 458 | mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay); |
| 459 | queue_delayed_work(o2net_wq, &nn->nn_connect_work, delay); | 459 | queue_delayed_work(o2net_wq, &nn->nn_connect_work, delay); |
| @@ -1552,12 +1552,11 @@ static void o2net_connect_expired(struct work_struct *work) | |||
| 1552 | 1552 | ||
| 1553 | spin_lock(&nn->nn_lock); | 1553 | spin_lock(&nn->nn_lock); |
| 1554 | if (!nn->nn_sc_valid) { | 1554 | if (!nn->nn_sc_valid) { |
| 1555 | struct o2nm_node *node = nn->nn_sc->sc_node; | ||
| 1556 | mlog(ML_ERROR, "no connection established with node %u after " | 1555 | mlog(ML_ERROR, "no connection established with node %u after " |
| 1557 | "%u.%u seconds, giving up and returning errors.\n", | 1556 | "%u.%u seconds, giving up and returning errors.\n", |
| 1558 | o2net_num_from_nn(nn), | 1557 | o2net_num_from_nn(nn), |
| 1559 | o2net_idle_timeout(node) / 1000, | 1558 | o2net_idle_timeout(NULL) / 1000, |
| 1560 | o2net_idle_timeout(node) % 1000); | 1559 | o2net_idle_timeout(NULL) % 1000); |
| 1561 | 1560 | ||
| 1562 | o2net_set_nn_state(nn, NULL, 0, -ENOTCONN); | 1561 | o2net_set_nn_state(nn, NULL, 0, -ENOTCONN); |
| 1563 | } | 1562 | } |
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 9843ee17ea27..dc8ea666efdb 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h | |||
| @@ -176,6 +176,7 @@ struct dlm_mig_lockres_priv | |||
| 176 | { | 176 | { |
| 177 | struct dlm_lock_resource *lockres; | 177 | struct dlm_lock_resource *lockres; |
| 178 | u8 real_master; | 178 | u8 real_master; |
| 179 | u8 extra_ref; | ||
| 179 | }; | 180 | }; |
| 180 | 181 | ||
| 181 | struct dlm_assert_master_priv | 182 | struct dlm_assert_master_priv |
| @@ -602,17 +603,19 @@ enum dlm_query_join_response_code { | |||
| 602 | JOIN_PROTOCOL_MISMATCH, | 603 | JOIN_PROTOCOL_MISMATCH, |
| 603 | }; | 604 | }; |
| 604 | 605 | ||
| 606 | struct dlm_query_join_packet { | ||
| 607 | u8 code; /* Response code. dlm_minor and fs_minor | ||
| 608 | are only valid if this is JOIN_OK */ | ||
| 609 | u8 dlm_minor; /* The minor version of the protocol the | ||
| 610 | dlm is speaking. */ | ||
| 611 | u8 fs_minor; /* The minor version of the protocol the | ||
| 612 | filesystem is speaking. */ | ||
| 613 | u8 reserved; | ||
| 614 | }; | ||
| 615 | |||
| 605 | union dlm_query_join_response { | 616 | union dlm_query_join_response { |
| 606 | u32 intval; | 617 | u32 intval; |
| 607 | struct { | 618 | struct dlm_query_join_packet packet; |
| 608 | u8 code; /* Response code. dlm_minor and fs_minor | ||
| 609 | are only valid if this is JOIN_OK */ | ||
| 610 | u8 dlm_minor; /* The minor version of the protocol the | ||
| 611 | dlm is speaking. */ | ||
| 612 | u8 fs_minor; /* The minor version of the protocol the | ||
| 613 | filesystem is speaking. */ | ||
| 614 | u8 reserved; | ||
| 615 | } packet; | ||
| 616 | }; | 619 | }; |
| 617 | 620 | ||
| 618 | struct dlm_lock_request | 621 | struct dlm_lock_request |
diff --git a/fs/ocfs2/dlm/dlmconvert.c b/fs/ocfs2/dlm/dlmconvert.c index ecb4d997221e..75997b4deaf3 100644 --- a/fs/ocfs2/dlm/dlmconvert.c +++ b/fs/ocfs2/dlm/dlmconvert.c | |||
| @@ -487,7 +487,7 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 487 | "cookie=%u:%llu\n", | 487 | "cookie=%u:%llu\n", |
| 488 | dlm_get_lock_cookie_node(be64_to_cpu(cnv->cookie)), | 488 | dlm_get_lock_cookie_node(be64_to_cpu(cnv->cookie)), |
| 489 | dlm_get_lock_cookie_seq(be64_to_cpu(cnv->cookie))); | 489 | dlm_get_lock_cookie_seq(be64_to_cpu(cnv->cookie))); |
| 490 | __dlm_print_one_lock_resource(res); | 490 | dlm_print_one_lock_resource(res); |
| 491 | goto leave; | 491 | goto leave; |
| 492 | } | 492 | } |
| 493 | 493 | ||
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 638d2ebb892b..0879d86113e3 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c | |||
| @@ -713,14 +713,46 @@ static int dlm_query_join_proto_check(char *proto_type, int node, | |||
| 713 | return rc; | 713 | return rc; |
| 714 | } | 714 | } |
| 715 | 715 | ||
| 716 | /* | ||
| 717 | * struct dlm_query_join_packet is made up of four one-byte fields. They | ||
| 718 | * are effectively in big-endian order already. However, little-endian | ||
| 719 | * machines swap them before putting the packet on the wire (because | ||
| 720 | * query_join's response is a status, and that status is treated as a u32 | ||
| 721 | * on the wire). Thus, a big-endian and little-endian machines will treat | ||
| 722 | * this structure differently. | ||
| 723 | * | ||
| 724 | * The solution is to have little-endian machines swap the structure when | ||
| 725 | * converting from the structure to the u32 representation. This will | ||
| 726 | * result in the structure having the correct format on the wire no matter | ||
| 727 | * the host endian format. | ||
| 728 | */ | ||
| 729 | static void dlm_query_join_packet_to_wire(struct dlm_query_join_packet *packet, | ||
| 730 | u32 *wire) | ||
| 731 | { | ||
| 732 | union dlm_query_join_response response; | ||
| 733 | |||
| 734 | response.packet = *packet; | ||
| 735 | *wire = cpu_to_be32(response.intval); | ||
| 736 | } | ||
| 737 | |||
| 738 | static void dlm_query_join_wire_to_packet(u32 wire, | ||
| 739 | struct dlm_query_join_packet *packet) | ||
| 740 | { | ||
| 741 | union dlm_query_join_response response; | ||
| 742 | |||
| 743 | response.intval = cpu_to_be32(wire); | ||
| 744 | *packet = response.packet; | ||
| 745 | } | ||
| 746 | |||
| 716 | static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | 747 | static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, |
| 717 | void **ret_data) | 748 | void **ret_data) |
| 718 | { | 749 | { |
| 719 | struct dlm_query_join_request *query; | 750 | struct dlm_query_join_request *query; |
| 720 | union dlm_query_join_response response = { | 751 | struct dlm_query_join_packet packet = { |
| 721 | .packet.code = JOIN_DISALLOW, | 752 | .code = JOIN_DISALLOW, |
| 722 | }; | 753 | }; |
| 723 | struct dlm_ctxt *dlm = NULL; | 754 | struct dlm_ctxt *dlm = NULL; |
| 755 | u32 response; | ||
| 724 | u8 nodenum; | 756 | u8 nodenum; |
| 725 | 757 | ||
| 726 | query = (struct dlm_query_join_request *) msg->buf; | 758 | query = (struct dlm_query_join_request *) msg->buf; |
| @@ -737,11 +769,11 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 737 | mlog(0, "node %u is not in our live map yet\n", | 769 | mlog(0, "node %u is not in our live map yet\n", |
| 738 | query->node_idx); | 770 | query->node_idx); |
| 739 | 771 | ||
| 740 | response.packet.code = JOIN_DISALLOW; | 772 | packet.code = JOIN_DISALLOW; |
| 741 | goto respond; | 773 | goto respond; |
| 742 | } | 774 | } |
| 743 | 775 | ||
| 744 | response.packet.code = JOIN_OK_NO_MAP; | 776 | packet.code = JOIN_OK_NO_MAP; |
| 745 | 777 | ||
| 746 | spin_lock(&dlm_domain_lock); | 778 | spin_lock(&dlm_domain_lock); |
| 747 | dlm = __dlm_lookup_domain_full(query->domain, query->name_len); | 779 | dlm = __dlm_lookup_domain_full(query->domain, query->name_len); |
| @@ -760,7 +792,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 760 | mlog(0, "disallow join as node %u does not " | 792 | mlog(0, "disallow join as node %u does not " |
| 761 | "have node %u in its nodemap\n", | 793 | "have node %u in its nodemap\n", |
| 762 | query->node_idx, nodenum); | 794 | query->node_idx, nodenum); |
| 763 | response.packet.code = JOIN_DISALLOW; | 795 | packet.code = JOIN_DISALLOW; |
| 764 | goto unlock_respond; | 796 | goto unlock_respond; |
| 765 | } | 797 | } |
| 766 | } | 798 | } |
| @@ -780,23 +812,23 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 780 | /*If this is a brand new context and we | 812 | /*If this is a brand new context and we |
| 781 | * haven't started our join process yet, then | 813 | * haven't started our join process yet, then |
| 782 | * the other node won the race. */ | 814 | * the other node won the race. */ |
| 783 | response.packet.code = JOIN_OK_NO_MAP; | 815 | packet.code = JOIN_OK_NO_MAP; |
| 784 | } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { | 816 | } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { |
| 785 | /* Disallow parallel joins. */ | 817 | /* Disallow parallel joins. */ |
| 786 | response.packet.code = JOIN_DISALLOW; | 818 | packet.code = JOIN_DISALLOW; |
| 787 | } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { | 819 | } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { |
| 788 | mlog(0, "node %u trying to join, but recovery " | 820 | mlog(0, "node %u trying to join, but recovery " |
| 789 | "is ongoing.\n", bit); | 821 | "is ongoing.\n", bit); |
| 790 | response.packet.code = JOIN_DISALLOW; | 822 | packet.code = JOIN_DISALLOW; |
| 791 | } else if (test_bit(bit, dlm->recovery_map)) { | 823 | } else if (test_bit(bit, dlm->recovery_map)) { |
| 792 | mlog(0, "node %u trying to join, but it " | 824 | mlog(0, "node %u trying to join, but it " |
| 793 | "still needs recovery.\n", bit); | 825 | "still needs recovery.\n", bit); |
| 794 | response.packet.code = JOIN_DISALLOW; | 826 | packet.code = JOIN_DISALLOW; |
| 795 | } else if (test_bit(bit, dlm->domain_map)) { | 827 | } else if (test_bit(bit, dlm->domain_map)) { |
| 796 | mlog(0, "node %u trying to join, but it " | 828 | mlog(0, "node %u trying to join, but it " |
| 797 | "is still in the domain! needs recovery?\n", | 829 | "is still in the domain! needs recovery?\n", |
| 798 | bit); | 830 | bit); |
| 799 | response.packet.code = JOIN_DISALLOW; | 831 | packet.code = JOIN_DISALLOW; |
| 800 | } else { | 832 | } else { |
| 801 | /* Alright we're fully a part of this domain | 833 | /* Alright we're fully a part of this domain |
| 802 | * so we keep some state as to who's joining | 834 | * so we keep some state as to who's joining |
| @@ -807,19 +839,15 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 807 | if (dlm_query_join_proto_check("DLM", bit, | 839 | if (dlm_query_join_proto_check("DLM", bit, |
| 808 | &dlm->dlm_locking_proto, | 840 | &dlm->dlm_locking_proto, |
| 809 | &query->dlm_proto)) { | 841 | &query->dlm_proto)) { |
| 810 | response.packet.code = | 842 | packet.code = JOIN_PROTOCOL_MISMATCH; |
| 811 | JOIN_PROTOCOL_MISMATCH; | ||
| 812 | } else if (dlm_query_join_proto_check("fs", bit, | 843 | } else if (dlm_query_join_proto_check("fs", bit, |
| 813 | &dlm->fs_locking_proto, | 844 | &dlm->fs_locking_proto, |
| 814 | &query->fs_proto)) { | 845 | &query->fs_proto)) { |
| 815 | response.packet.code = | 846 | packet.code = JOIN_PROTOCOL_MISMATCH; |
| 816 | JOIN_PROTOCOL_MISMATCH; | ||
| 817 | } else { | 847 | } else { |
| 818 | response.packet.dlm_minor = | 848 | packet.dlm_minor = query->dlm_proto.pv_minor; |
| 819 | query->dlm_proto.pv_minor; | 849 | packet.fs_minor = query->fs_proto.pv_minor; |
| 820 | response.packet.fs_minor = | 850 | packet.code = JOIN_OK; |
| 821 | query->fs_proto.pv_minor; | ||
| 822 | response.packet.code = JOIN_OK; | ||
| 823 | __dlm_set_joining_node(dlm, query->node_idx); | 851 | __dlm_set_joining_node(dlm, query->node_idx); |
| 824 | } | 852 | } |
| 825 | } | 853 | } |
| @@ -830,9 +858,10 @@ unlock_respond: | |||
| 830 | spin_unlock(&dlm_domain_lock); | 858 | spin_unlock(&dlm_domain_lock); |
| 831 | 859 | ||
| 832 | respond: | 860 | respond: |
| 833 | mlog(0, "We respond with %u\n", response.packet.code); | 861 | mlog(0, "We respond with %u\n", packet.code); |
| 834 | 862 | ||
| 835 | return response.intval; | 863 | dlm_query_join_packet_to_wire(&packet, &response); |
| 864 | return response; | ||
| 836 | } | 865 | } |
| 837 | 866 | ||
| 838 | static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, | 867 | static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, |
| @@ -937,7 +966,7 @@ static int dlm_send_join_cancels(struct dlm_ctxt *dlm, | |||
| 937 | sizeof(unsigned long))) { | 966 | sizeof(unsigned long))) { |
| 938 | mlog(ML_ERROR, | 967 | mlog(ML_ERROR, |
| 939 | "map_size %u != BITS_TO_LONGS(O2NM_MAX_NODES) %u\n", | 968 | "map_size %u != BITS_TO_LONGS(O2NM_MAX_NODES) %u\n", |
| 940 | map_size, BITS_TO_LONGS(O2NM_MAX_NODES)); | 969 | map_size, (unsigned)BITS_TO_LONGS(O2NM_MAX_NODES)); |
| 941 | return -EINVAL; | 970 | return -EINVAL; |
| 942 | } | 971 | } |
| 943 | 972 | ||
| @@ -968,7 +997,8 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
| 968 | { | 997 | { |
| 969 | int status; | 998 | int status; |
| 970 | struct dlm_query_join_request join_msg; | 999 | struct dlm_query_join_request join_msg; |
| 971 | union dlm_query_join_response join_resp; | 1000 | struct dlm_query_join_packet packet; |
| 1001 | u32 join_resp; | ||
| 972 | 1002 | ||
| 973 | mlog(0, "querying node %d\n", node); | 1003 | mlog(0, "querying node %d\n", node); |
| 974 | 1004 | ||
| @@ -984,11 +1014,12 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
| 984 | 1014 | ||
| 985 | status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, | 1015 | status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, |
| 986 | sizeof(join_msg), node, | 1016 | sizeof(join_msg), node, |
| 987 | &join_resp.intval); | 1017 | &join_resp); |
| 988 | if (status < 0 && status != -ENOPROTOOPT) { | 1018 | if (status < 0 && status != -ENOPROTOOPT) { |
| 989 | mlog_errno(status); | 1019 | mlog_errno(status); |
| 990 | goto bail; | 1020 | goto bail; |
| 991 | } | 1021 | } |
| 1022 | dlm_query_join_wire_to_packet(join_resp, &packet); | ||
| 992 | 1023 | ||
| 993 | /* -ENOPROTOOPT from the net code means the other side isn't | 1024 | /* -ENOPROTOOPT from the net code means the other side isn't |
| 994 | listening for our message type -- that's fine, it means | 1025 | listening for our message type -- that's fine, it means |
| @@ -997,10 +1028,10 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
| 997 | if (status == -ENOPROTOOPT) { | 1028 | if (status == -ENOPROTOOPT) { |
| 998 | status = 0; | 1029 | status = 0; |
| 999 | *response = JOIN_OK_NO_MAP; | 1030 | *response = JOIN_OK_NO_MAP; |
| 1000 | } else if (join_resp.packet.code == JOIN_DISALLOW || | 1031 | } else if (packet.code == JOIN_DISALLOW || |
| 1001 | join_resp.packet.code == JOIN_OK_NO_MAP) { | 1032 | packet.code == JOIN_OK_NO_MAP) { |
| 1002 | *response = join_resp.packet.code; | 1033 | *response = packet.code; |
| 1003 | } else if (join_resp.packet.code == JOIN_PROTOCOL_MISMATCH) { | 1034 | } else if (packet.code == JOIN_PROTOCOL_MISMATCH) { |
| 1004 | mlog(ML_NOTICE, | 1035 | mlog(ML_NOTICE, |
| 1005 | "This node requested DLM locking protocol %u.%u and " | 1036 | "This node requested DLM locking protocol %u.%u and " |
| 1006 | "filesystem locking protocol %u.%u. At least one of " | 1037 | "filesystem locking protocol %u.%u. At least one of " |
| @@ -1012,14 +1043,12 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
| 1012 | dlm->fs_locking_proto.pv_minor, | 1043 | dlm->fs_locking_proto.pv_minor, |
| 1013 | node); | 1044 | node); |
| 1014 | status = -EPROTO; | 1045 | status = -EPROTO; |
| 1015 | *response = join_resp.packet.code; | 1046 | *response = packet.code; |
| 1016 | } else if (join_resp.packet.code == JOIN_OK) { | 1047 | } else if (packet.code == JOIN_OK) { |
| 1017 | *response = join_resp.packet.code; | 1048 | *response = packet.code; |
| 1018 | /* Use the same locking protocol as the remote node */ | 1049 | /* Use the same locking protocol as the remote node */ |
| 1019 | dlm->dlm_locking_proto.pv_minor = | 1050 | dlm->dlm_locking_proto.pv_minor = packet.dlm_minor; |
| 1020 | join_resp.packet.dlm_minor; | 1051 | dlm->fs_locking_proto.pv_minor = packet.fs_minor; |
| 1021 | dlm->fs_locking_proto.pv_minor = | ||
| 1022 | join_resp.packet.fs_minor; | ||
| 1023 | mlog(0, | 1052 | mlog(0, |
| 1024 | "Node %d responds JOIN_OK with DLM locking protocol " | 1053 | "Node %d responds JOIN_OK with DLM locking protocol " |
| 1025 | "%u.%u and fs locking protocol %u.%u\n", | 1054 | "%u.%u and fs locking protocol %u.%u\n", |
| @@ -1031,11 +1060,11 @@ static int dlm_request_join(struct dlm_ctxt *dlm, | |||
| 1031 | } else { | 1060 | } else { |
| 1032 | status = -EINVAL; | 1061 | status = -EINVAL; |
| 1033 | mlog(ML_ERROR, "invalid response %d from node %u\n", | 1062 | mlog(ML_ERROR, "invalid response %d from node %u\n", |
| 1034 | join_resp.packet.code, node); | 1063 | packet.code, node); |
| 1035 | } | 1064 | } |
| 1036 | 1065 | ||
| 1037 | mlog(0, "status %d, node %d response is %d\n", status, node, | 1066 | mlog(0, "status %d, node %d response is %d\n", status, node, |
| 1038 | *response); | 1067 | *response); |
| 1039 | 1068 | ||
| 1040 | bail: | 1069 | bail: |
| 1041 | return status; | 1070 | return status; |
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index c92d1b19fc0b..ea6b89577860 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
| @@ -1663,7 +1663,12 @@ way_up_top: | |||
| 1663 | dlm_put_mle(tmpmle); | 1663 | dlm_put_mle(tmpmle); |
| 1664 | } | 1664 | } |
| 1665 | send_response: | 1665 | send_response: |
| 1666 | 1666 | /* | |
| 1667 | * __dlm_lookup_lockres() grabbed a reference to this lockres. | ||
| 1668 | * The reference is released by dlm_assert_master_worker() under | ||
| 1669 | * the call to dlm_dispatch_assert_master(). If | ||
| 1670 | * dlm_assert_master_worker() isn't called, we drop it here. | ||
| 1671 | */ | ||
| 1667 | if (dispatch_assert) { | 1672 | if (dispatch_assert) { |
| 1668 | if (response != DLM_MASTER_RESP_YES) | 1673 | if (response != DLM_MASTER_RESP_YES) |
| 1669 | mlog(ML_ERROR, "invalid response %d\n", response); | 1674 | mlog(ML_ERROR, "invalid response %d\n", response); |
| @@ -1678,7 +1683,11 @@ send_response: | |||
| 1678 | if (ret < 0) { | 1683 | if (ret < 0) { |
| 1679 | mlog(ML_ERROR, "failed to dispatch assert master work\n"); | 1684 | mlog(ML_ERROR, "failed to dispatch assert master work\n"); |
| 1680 | response = DLM_MASTER_RESP_ERROR; | 1685 | response = DLM_MASTER_RESP_ERROR; |
| 1686 | dlm_lockres_put(res); | ||
| 1681 | } | 1687 | } |
| 1688 | } else { | ||
| 1689 | if (res) | ||
| 1690 | dlm_lockres_put(res); | ||
| 1682 | } | 1691 | } |
| 1683 | 1692 | ||
| 1684 | dlm_put(dlm); | 1693 | dlm_put(dlm); |
| @@ -2348,7 +2357,7 @@ int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 2348 | mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref " | 2357 | mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref " |
| 2349 | "but it is already dropped!\n", dlm->name, | 2358 | "but it is already dropped!\n", dlm->name, |
| 2350 | res->lockname.len, res->lockname.name, node); | 2359 | res->lockname.len, res->lockname.name, node); |
| 2351 | __dlm_print_one_lock_resource(res); | 2360 | dlm_print_one_lock_resource(res); |
| 2352 | } | 2361 | } |
| 2353 | ret = 0; | 2362 | ret = 0; |
| 2354 | goto done; | 2363 | goto done; |
| @@ -2408,7 +2417,7 @@ static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data) | |||
| 2408 | mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref " | 2417 | mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref " |
| 2409 | "but it is already dropped!\n", dlm->name, | 2418 | "but it is already dropped!\n", dlm->name, |
| 2410 | res->lockname.len, res->lockname.name, node); | 2419 | res->lockname.len, res->lockname.name, node); |
| 2411 | __dlm_print_one_lock_resource(res); | 2420 | dlm_print_one_lock_resource(res); |
| 2412 | } | 2421 | } |
| 2413 | 2422 | ||
| 2414 | dlm_lockres_put(res); | 2423 | dlm_lockres_put(res); |
| @@ -2933,6 +2942,9 @@ static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm, | |||
| 2933 | dlm_lockres_clear_refmap_bit(lock->ml.node, res); | 2942 | dlm_lockres_clear_refmap_bit(lock->ml.node, res); |
| 2934 | list_del_init(&lock->list); | 2943 | list_del_init(&lock->list); |
| 2935 | dlm_lock_put(lock); | 2944 | dlm_lock_put(lock); |
| 2945 | /* In a normal unlock, we would have added a | ||
| 2946 | * DLM_UNLOCK_FREE_LOCK action. Force it. */ | ||
| 2947 | dlm_lock_put(lock); | ||
| 2936 | } | 2948 | } |
| 2937 | } | 2949 | } |
| 2938 | queue++; | 2950 | queue++; |
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 91f747b8a538..bcb9260c3735 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c | |||
| @@ -519,9 +519,9 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) | |||
| 519 | return 0; | 519 | return 0; |
| 520 | 520 | ||
| 521 | master_here: | 521 | master_here: |
| 522 | mlog(0, "(%d) mastering recovery of %s:%u here(this=%u)!\n", | 522 | mlog(ML_NOTICE, "(%d) Node %u is the Recovery Master for the Dead Node " |
| 523 | task_pid_nr(dlm->dlm_reco_thread_task), | 523 | "%u for Domain %s\n", task_pid_nr(dlm->dlm_reco_thread_task), |
| 524 | dlm->name, dlm->reco.dead_node, dlm->node_num); | 524 | dlm->node_num, dlm->reco.dead_node, dlm->name); |
| 525 | 525 | ||
| 526 | status = dlm_remaster_locks(dlm, dlm->reco.dead_node); | 526 | status = dlm_remaster_locks(dlm, dlm->reco.dead_node); |
| 527 | if (status < 0) { | 527 | if (status < 0) { |
| @@ -1191,7 +1191,7 @@ static int dlm_add_lock_to_array(struct dlm_lock *lock, | |||
| 1191 | (ml->type == LKM_EXMODE || | 1191 | (ml->type == LKM_EXMODE || |
| 1192 | memcmp(mres->lvb, lock->lksb->lvb, DLM_LVB_LEN))) { | 1192 | memcmp(mres->lvb, lock->lksb->lvb, DLM_LVB_LEN))) { |
| 1193 | mlog(ML_ERROR, "mismatched lvbs!\n"); | 1193 | mlog(ML_ERROR, "mismatched lvbs!\n"); |
| 1194 | __dlm_print_one_lock_resource(lock->lockres); | 1194 | dlm_print_one_lock_resource(lock->lockres); |
| 1195 | BUG(); | 1195 | BUG(); |
| 1196 | } | 1196 | } |
| 1197 | memcpy(mres->lvb, lock->lksb->lvb, DLM_LVB_LEN); | 1197 | memcpy(mres->lvb, lock->lksb->lvb, DLM_LVB_LEN); |
| @@ -1327,6 +1327,7 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 1327 | (struct dlm_migratable_lockres *)msg->buf; | 1327 | (struct dlm_migratable_lockres *)msg->buf; |
| 1328 | int ret = 0; | 1328 | int ret = 0; |
| 1329 | u8 real_master; | 1329 | u8 real_master; |
| 1330 | u8 extra_refs = 0; | ||
| 1330 | char *buf = NULL; | 1331 | char *buf = NULL; |
| 1331 | struct dlm_work_item *item = NULL; | 1332 | struct dlm_work_item *item = NULL; |
| 1332 | struct dlm_lock_resource *res = NULL; | 1333 | struct dlm_lock_resource *res = NULL; |
| @@ -1404,16 +1405,28 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 1404 | __dlm_insert_lockres(dlm, res); | 1405 | __dlm_insert_lockres(dlm, res); |
| 1405 | spin_unlock(&dlm->spinlock); | 1406 | spin_unlock(&dlm->spinlock); |
| 1406 | 1407 | ||
| 1408 | /* Add an extra ref for this lock-less lockres lest the | ||
| 1409 | * dlm_thread purges it before we get the chance to add | ||
| 1410 | * locks to it */ | ||
| 1411 | dlm_lockres_get(res); | ||
| 1412 | |||
| 1413 | /* There are three refs that need to be put. | ||
| 1414 | * 1. Taken above. | ||
| 1415 | * 2. kref_init in dlm_new_lockres()->dlm_init_lockres(). | ||
| 1416 | * 3. dlm_lookup_lockres() | ||
| 1417 | * The first one is handled at the end of this function. The | ||
| 1418 | * other two are handled in the worker thread after locks have | ||
| 1419 | * been attached. Yes, we don't wait for purge time to match | ||
| 1420 | * kref_init. The lockres will still have atleast one ref | ||
| 1421 | * added because it is in the hash __dlm_insert_lockres() */ | ||
| 1422 | extra_refs++; | ||
| 1423 | |||
| 1407 | /* now that the new lockres is inserted, | 1424 | /* now that the new lockres is inserted, |
| 1408 | * make it usable by other processes */ | 1425 | * make it usable by other processes */ |
| 1409 | spin_lock(&res->spinlock); | 1426 | spin_lock(&res->spinlock); |
| 1410 | res->state &= ~DLM_LOCK_RES_IN_PROGRESS; | 1427 | res->state &= ~DLM_LOCK_RES_IN_PROGRESS; |
| 1411 | spin_unlock(&res->spinlock); | 1428 | spin_unlock(&res->spinlock); |
| 1412 | wake_up(&res->wq); | 1429 | wake_up(&res->wq); |
| 1413 | |||
| 1414 | /* add an extra ref for just-allocated lockres | ||
| 1415 | * otherwise the lockres will be purged immediately */ | ||
| 1416 | dlm_lockres_get(res); | ||
| 1417 | } | 1430 | } |
| 1418 | 1431 | ||
| 1419 | /* at this point we have allocated everything we need, | 1432 | /* at this point we have allocated everything we need, |
| @@ -1443,12 +1456,17 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 1443 | dlm_init_work_item(dlm, item, dlm_mig_lockres_worker, buf); | 1456 | dlm_init_work_item(dlm, item, dlm_mig_lockres_worker, buf); |
| 1444 | item->u.ml.lockres = res; /* already have a ref */ | 1457 | item->u.ml.lockres = res; /* already have a ref */ |
| 1445 | item->u.ml.real_master = real_master; | 1458 | item->u.ml.real_master = real_master; |
| 1459 | item->u.ml.extra_ref = extra_refs; | ||
| 1446 | spin_lock(&dlm->work_lock); | 1460 | spin_lock(&dlm->work_lock); |
| 1447 | list_add_tail(&item->list, &dlm->work_list); | 1461 | list_add_tail(&item->list, &dlm->work_list); |
| 1448 | spin_unlock(&dlm->work_lock); | 1462 | spin_unlock(&dlm->work_lock); |
| 1449 | queue_work(dlm->dlm_worker, &dlm->dispatched_work); | 1463 | queue_work(dlm->dlm_worker, &dlm->dispatched_work); |
| 1450 | 1464 | ||
| 1451 | leave: | 1465 | leave: |
| 1466 | /* One extra ref taken needs to be put here */ | ||
| 1467 | if (extra_refs) | ||
| 1468 | dlm_lockres_put(res); | ||
| 1469 | |||
| 1452 | dlm_put(dlm); | 1470 | dlm_put(dlm); |
| 1453 | if (ret < 0) { | 1471 | if (ret < 0) { |
| 1454 | if (buf) | 1472 | if (buf) |
| @@ -1464,17 +1482,19 @@ leave: | |||
| 1464 | 1482 | ||
| 1465 | static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data) | 1483 | static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data) |
| 1466 | { | 1484 | { |
| 1467 | struct dlm_ctxt *dlm = data; | 1485 | struct dlm_ctxt *dlm; |
| 1468 | struct dlm_migratable_lockres *mres; | 1486 | struct dlm_migratable_lockres *mres; |
| 1469 | int ret = 0; | 1487 | int ret = 0; |
| 1470 | struct dlm_lock_resource *res; | 1488 | struct dlm_lock_resource *res; |
| 1471 | u8 real_master; | 1489 | u8 real_master; |
| 1490 | u8 extra_ref; | ||
| 1472 | 1491 | ||
| 1473 | dlm = item->dlm; | 1492 | dlm = item->dlm; |
| 1474 | mres = (struct dlm_migratable_lockres *)data; | 1493 | mres = (struct dlm_migratable_lockres *)data; |
| 1475 | 1494 | ||
| 1476 | res = item->u.ml.lockres; | 1495 | res = item->u.ml.lockres; |
| 1477 | real_master = item->u.ml.real_master; | 1496 | real_master = item->u.ml.real_master; |
| 1497 | extra_ref = item->u.ml.extra_ref; | ||
| 1478 | 1498 | ||
| 1479 | if (real_master == DLM_LOCK_RES_OWNER_UNKNOWN) { | 1499 | if (real_master == DLM_LOCK_RES_OWNER_UNKNOWN) { |
| 1480 | /* this case is super-rare. only occurs if | 1500 | /* this case is super-rare. only occurs if |
| @@ -1517,6 +1537,12 @@ again: | |||
| 1517 | } | 1537 | } |
| 1518 | 1538 | ||
| 1519 | leave: | 1539 | leave: |
| 1540 | /* See comment in dlm_mig_lockres_handler() */ | ||
| 1541 | if (res) { | ||
| 1542 | if (extra_ref) | ||
| 1543 | dlm_lockres_put(res); | ||
| 1544 | dlm_lockres_put(res); | ||
| 1545 | } | ||
| 1520 | kfree(data); | 1546 | kfree(data); |
| 1521 | mlog_exit(ret); | 1547 | mlog_exit(ret); |
| 1522 | } | 1548 | } |
| @@ -1644,7 +1670,8 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 1644 | /* retry!? */ | 1670 | /* retry!? */ |
| 1645 | BUG(); | 1671 | BUG(); |
| 1646 | } | 1672 | } |
| 1647 | } | 1673 | } else /* put.. incase we are not the master */ |
| 1674 | dlm_lockres_put(res); | ||
| 1648 | spin_unlock(&res->spinlock); | 1675 | spin_unlock(&res->spinlock); |
| 1649 | } | 1676 | } |
| 1650 | spin_unlock(&dlm->spinlock); | 1677 | spin_unlock(&dlm->spinlock); |
| @@ -1921,6 +1948,7 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm, | |||
| 1921 | "Recovering res %s:%.*s, is already on recovery list!\n", | 1948 | "Recovering res %s:%.*s, is already on recovery list!\n", |
| 1922 | dlm->name, res->lockname.len, res->lockname.name); | 1949 | dlm->name, res->lockname.len, res->lockname.name); |
| 1923 | list_del_init(&res->recovering); | 1950 | list_del_init(&res->recovering); |
| 1951 | dlm_lockres_put(res); | ||
| 1924 | } | 1952 | } |
| 1925 | /* We need to hold a reference while on the recovery list */ | 1953 | /* We need to hold a reference while on the recovery list */ |
| 1926 | dlm_lockres_get(res); | 1954 | dlm_lockres_get(res); |
| @@ -2130,11 +2158,16 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, | |||
| 2130 | assert_spin_locked(&dlm->spinlock); | 2158 | assert_spin_locked(&dlm->spinlock); |
| 2131 | assert_spin_locked(&res->spinlock); | 2159 | assert_spin_locked(&res->spinlock); |
| 2132 | 2160 | ||
| 2161 | /* We do two dlm_lock_put(). One for removing from list and the other is | ||
| 2162 | * to force the DLM_UNLOCK_FREE_LOCK action so as to free the locks */ | ||
| 2163 | |||
| 2133 | /* TODO: check pending_asts, pending_basts here */ | 2164 | /* TODO: check pending_asts, pending_basts here */ |
| 2134 | list_for_each_entry_safe(lock, next, &res->granted, list) { | 2165 | list_for_each_entry_safe(lock, next, &res->granted, list) { |
| 2135 | if (lock->ml.node == dead_node) { | 2166 | if (lock->ml.node == dead_node) { |
| 2136 | list_del_init(&lock->list); | 2167 | list_del_init(&lock->list); |
| 2137 | dlm_lock_put(lock); | 2168 | dlm_lock_put(lock); |
| 2169 | /* Can't schedule DLM_UNLOCK_FREE_LOCK - do manually */ | ||
| 2170 | dlm_lock_put(lock); | ||
| 2138 | freed++; | 2171 | freed++; |
| 2139 | } | 2172 | } |
| 2140 | } | 2173 | } |
| @@ -2142,6 +2175,8 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, | |||
| 2142 | if (lock->ml.node == dead_node) { | 2175 | if (lock->ml.node == dead_node) { |
| 2143 | list_del_init(&lock->list); | 2176 | list_del_init(&lock->list); |
| 2144 | dlm_lock_put(lock); | 2177 | dlm_lock_put(lock); |
| 2178 | /* Can't schedule DLM_UNLOCK_FREE_LOCK - do manually */ | ||
| 2179 | dlm_lock_put(lock); | ||
| 2145 | freed++; | 2180 | freed++; |
| 2146 | } | 2181 | } |
| 2147 | } | 2182 | } |
| @@ -2149,6 +2184,8 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, | |||
| 2149 | if (lock->ml.node == dead_node) { | 2184 | if (lock->ml.node == dead_node) { |
| 2150 | list_del_init(&lock->list); | 2185 | list_del_init(&lock->list); |
| 2151 | dlm_lock_put(lock); | 2186 | dlm_lock_put(lock); |
| 2187 | /* Can't schedule DLM_UNLOCK_FREE_LOCK - do manually */ | ||
| 2188 | dlm_lock_put(lock); | ||
| 2152 | freed++; | 2189 | freed++; |
| 2153 | } | 2190 | } |
| 2154 | } | 2191 | } |
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c index cebd089f8955..4060bb328bc8 100644 --- a/fs/ocfs2/dlm/dlmthread.c +++ b/fs/ocfs2/dlm/dlmthread.c | |||
| @@ -176,12 +176,14 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm, | |||
| 176 | res->lockname.name, master); | 176 | res->lockname.name, master); |
| 177 | 177 | ||
| 178 | if (!master) { | 178 | if (!master) { |
| 179 | /* drop spinlock... retake below */ | ||
| 180 | spin_unlock(&dlm->spinlock); | ||
| 181 | |||
| 179 | spin_lock(&res->spinlock); | 182 | spin_lock(&res->spinlock); |
| 180 | /* This ensures that clear refmap is sent after the set */ | 183 | /* This ensures that clear refmap is sent after the set */ |
| 181 | __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG); | 184 | __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG); |
| 182 | spin_unlock(&res->spinlock); | 185 | spin_unlock(&res->spinlock); |
| 183 | /* drop spinlock to do messaging, retake below */ | 186 | |
| 184 | spin_unlock(&dlm->spinlock); | ||
| 185 | /* clear our bit from the master's refmap, ignore errors */ | 187 | /* clear our bit from the master's refmap, ignore errors */ |
| 186 | ret = dlm_drop_lockres_ref(dlm, res); | 188 | ret = dlm_drop_lockres_ref(dlm, res); |
| 187 | if (ret < 0) { | 189 | if (ret < 0) { |
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index f7794306b2bd..1f1873bf41fb 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
| @@ -2409,7 +2409,7 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v) | |||
| 2409 | return 0; | 2409 | return 0; |
| 2410 | } | 2410 | } |
| 2411 | 2411 | ||
| 2412 | static struct seq_operations ocfs2_dlm_seq_ops = { | 2412 | static const struct seq_operations ocfs2_dlm_seq_ops = { |
| 2413 | .start = ocfs2_dlm_seq_start, | 2413 | .start = ocfs2_dlm_seq_start, |
| 2414 | .stop = ocfs2_dlm_seq_stop, | 2414 | .stop = ocfs2_dlm_seq_stop, |
| 2415 | .next = ocfs2_dlm_seq_next, | 2415 | .next = ocfs2_dlm_seq_next, |
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c index 37835ffcb039..8166968e9015 100644 --- a/fs/ocfs2/resize.c +++ b/fs/ocfs2/resize.c | |||
| @@ -597,7 +597,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) | |||
| 597 | memset(cr, 0, sizeof(struct ocfs2_chain_rec)); | 597 | memset(cr, 0, sizeof(struct ocfs2_chain_rec)); |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | cr->c_blkno = le64_to_cpu(input->group); | 600 | cr->c_blkno = cpu_to_le64(input->group); |
| 601 | le32_add_cpu(&cr->c_total, input->clusters * cl_bpc); | 601 | le32_add_cpu(&cr->c_total, input->clusters * cl_bpc); |
| 602 | le32_add_cpu(&cr->c_free, input->frees * cl_bpc); | 602 | le32_add_cpu(&cr->c_free, input->frees * cl_bpc); |
| 603 | 603 | ||
diff --git a/include/linux/memstick.h b/include/linux/memstick.h index 334d059d6794..b7ee25888836 100644 --- a/include/linux/memstick.h +++ b/include/linux/memstick.h | |||
| @@ -22,6 +22,8 @@ struct ms_status_register { | |||
| 22 | unsigned char reserved; | 22 | unsigned char reserved; |
| 23 | unsigned char interrupt; | 23 | unsigned char interrupt; |
| 24 | #define MEMSTICK_INT_CMDNAK 0x0001 | 24 | #define MEMSTICK_INT_CMDNAK 0x0001 |
| 25 | #define MEMSTICK_INT_IOREQ 0x0008 | ||
| 26 | #define MEMSTICK_INT_IOBREQ 0x0010 | ||
| 25 | #define MEMSTICK_INT_BREQ 0x0020 | 27 | #define MEMSTICK_INT_BREQ 0x0020 |
| 26 | #define MEMSTICK_INT_ERR 0x0040 | 28 | #define MEMSTICK_INT_ERR 0x0040 |
| 27 | #define MEMSTICK_INT_CED 0x0080 | 29 | #define MEMSTICK_INT_CED 0x0080 |
| @@ -47,13 +49,17 @@ struct ms_status_register { | |||
| 47 | 49 | ||
| 48 | struct ms_id_register { | 50 | struct ms_id_register { |
| 49 | unsigned char type; | 51 | unsigned char type; |
| 50 | unsigned char reserved; | 52 | unsigned char if_mode; |
| 51 | unsigned char category; | 53 | unsigned char category; |
| 52 | unsigned char class; | 54 | unsigned char class; |
| 53 | } __attribute__((packed)); | 55 | } __attribute__((packed)); |
| 54 | 56 | ||
| 55 | struct ms_param_register { | 57 | struct ms_param_register { |
| 56 | unsigned char system; | 58 | unsigned char system; |
| 59 | #define MEMSTICK_SYS_ATEN 0xc0 | ||
| 60 | #define MEMSTICK_SYS_BAMD 0x80 | ||
| 61 | #define MEMSTICK_SYS_PAM 0x08 | ||
| 62 | |||
| 57 | unsigned char block_address_msb; | 63 | unsigned char block_address_msb; |
| 58 | unsigned short block_address; | 64 | unsigned short block_address; |
| 59 | unsigned char cp; | 65 | unsigned char cp; |
| @@ -90,16 +96,48 @@ struct ms_register { | |||
| 90 | 96 | ||
| 91 | struct mspro_param_register { | 97 | struct mspro_param_register { |
| 92 | unsigned char system; | 98 | unsigned char system; |
| 99 | #define MEMSTICK_SYS_SERIAL 0x80 | ||
| 100 | #define MEMSTICK_SYS_PAR4 0x00 | ||
| 101 | #define MEMSTICK_SYS_PAR8 0x40 | ||
| 102 | |||
| 103 | unsigned short data_count; | ||
| 104 | unsigned int data_address; | ||
| 105 | unsigned char tpc_param; | ||
| 106 | } __attribute__((packed)); | ||
| 107 | |||
| 108 | struct mspro_io_info_register { | ||
| 109 | unsigned char version; | ||
| 110 | unsigned char io_category; | ||
| 111 | unsigned char current_req; | ||
| 112 | unsigned char card_opt_info; | ||
| 113 | unsigned char rdy_wait_time; | ||
| 114 | } __attribute__((packed)); | ||
| 115 | |||
| 116 | struct mspro_io_func_register { | ||
| 117 | unsigned char func_enable; | ||
| 118 | unsigned char func_select; | ||
| 119 | unsigned char func_intmask; | ||
| 120 | unsigned char transfer_mode; | ||
| 121 | } __attribute__((packed)); | ||
| 122 | |||
| 123 | struct mspro_io_cmd_register { | ||
| 124 | unsigned short tpc_param; | ||
| 93 | unsigned short data_count; | 125 | unsigned short data_count; |
| 94 | unsigned int data_address; | 126 | unsigned int data_address; |
| 95 | unsigned char cmd_param; | ||
| 96 | } __attribute__((packed)); | 127 | } __attribute__((packed)); |
| 97 | 128 | ||
| 98 | struct mspro_register { | 129 | struct mspro_register { |
| 99 | struct ms_status_register status; | 130 | struct ms_status_register status; |
| 100 | struct ms_id_register id; | 131 | struct ms_id_register id; |
| 101 | unsigned char reserved[8]; | 132 | unsigned char reserved0[8]; |
| 102 | struct mspro_param_register param; | 133 | struct mspro_param_register param; |
| 134 | unsigned char reserved1[8]; | ||
| 135 | struct mspro_io_info_register io_info; | ||
| 136 | struct mspro_io_func_register io_func; | ||
| 137 | unsigned char reserved2[7]; | ||
| 138 | struct mspro_io_cmd_register io_cmd; | ||
| 139 | unsigned char io_int; | ||
| 140 | unsigned char io_int_func; | ||
| 103 | } __attribute__((packed)); | 141 | } __attribute__((packed)); |
| 104 | 142 | ||
| 105 | struct ms_register_addr { | 143 | struct ms_register_addr { |
| @@ -110,49 +148,55 @@ struct ms_register_addr { | |||
| 110 | } __attribute__((packed)); | 148 | } __attribute__((packed)); |
| 111 | 149 | ||
| 112 | enum { | 150 | enum { |
| 151 | MS_TPC_READ_MG_STATUS = 0x01, | ||
| 113 | MS_TPC_READ_LONG_DATA = 0x02, | 152 | MS_TPC_READ_LONG_DATA = 0x02, |
| 114 | MS_TPC_READ_SHORT_DATA = 0x03, | 153 | MS_TPC_READ_SHORT_DATA = 0x03, |
| 154 | MS_TPC_READ_MG_DATA = 0x03, | ||
| 115 | MS_TPC_READ_REG = 0x04, | 155 | MS_TPC_READ_REG = 0x04, |
| 116 | MS_TPC_READ_IO_DATA = 0x05, /* unverified */ | 156 | MS_TPC_READ_QUAD_DATA = 0x05, |
| 157 | MS_TPC_READ_IO_DATA = 0x05, | ||
| 117 | MS_TPC_GET_INT = 0x07, | 158 | MS_TPC_GET_INT = 0x07, |
| 118 | MS_TPC_SET_RW_REG_ADRS = 0x08, | 159 | MS_TPC_SET_RW_REG_ADRS = 0x08, |
| 119 | MS_TPC_EX_SET_CMD = 0x09, | 160 | MS_TPC_EX_SET_CMD = 0x09, |
| 120 | MS_TPC_WRITE_IO_DATA = 0x0a, /* unverified */ | 161 | MS_TPC_WRITE_QUAD_DATA = 0x0a, |
| 162 | MS_TPC_WRITE_IO_DATA = 0x0a, | ||
| 121 | MS_TPC_WRITE_REG = 0x0b, | 163 | MS_TPC_WRITE_REG = 0x0b, |
| 122 | MS_TPC_WRITE_SHORT_DATA = 0x0c, | 164 | MS_TPC_WRITE_SHORT_DATA = 0x0c, |
| 165 | MS_TPC_WRITE_MG_DATA = 0x0c, | ||
| 123 | MS_TPC_WRITE_LONG_DATA = 0x0d, | 166 | MS_TPC_WRITE_LONG_DATA = 0x0d, |
| 124 | MS_TPC_SET_CMD = 0x0e | 167 | MS_TPC_SET_CMD = 0x0e |
| 125 | }; | 168 | }; |
| 126 | 169 | ||
| 127 | enum { | 170 | enum { |
| 128 | MS_CMD_BLOCK_END = 0x33, | 171 | MS_CMD_BLOCK_END = 0x33, |
| 129 | MS_CMD_RESET = 0x3c, | 172 | MS_CMD_RESET = 0x3c, |
| 130 | MS_CMD_BLOCK_WRITE = 0x55, | 173 | MS_CMD_BLOCK_WRITE = 0x55, |
| 131 | MS_CMD_SLEEP = 0x5a, | 174 | MS_CMD_SLEEP = 0x5a, |
| 132 | MS_CMD_BLOCK_ERASE = 0x99, | 175 | MS_CMD_BLOCK_ERASE = 0x99, |
| 133 | MS_CMD_BLOCK_READ = 0xaa, | 176 | MS_CMD_BLOCK_READ = 0xaa, |
| 134 | MS_CMD_CLEAR_BUF = 0xc3, | 177 | MS_CMD_CLEAR_BUF = 0xc3, |
| 135 | MS_CMD_FLASH_STOP = 0xcc, | 178 | MS_CMD_FLASH_STOP = 0xcc, |
| 136 | MSPRO_CMD_FORMAT = 0x10, | 179 | MS_CMD_LOAD_ID = 0x60, |
| 137 | MSPRO_CMD_SLEEP = 0x11, | 180 | MS_CMD_CMP_ICV = 0x7f, |
| 138 | MSPRO_CMD_READ_DATA = 0x20, | 181 | MSPRO_CMD_FORMAT = 0x10, |
| 139 | MSPRO_CMD_WRITE_DATA = 0x21, | 182 | MSPRO_CMD_SLEEP = 0x11, |
| 140 | MSPRO_CMD_READ_ATRB = 0x24, | 183 | MSPRO_CMD_WAKEUP = 0x12, |
| 141 | MSPRO_CMD_STOP = 0x25, | 184 | MSPRO_CMD_READ_DATA = 0x20, |
| 142 | MSPRO_CMD_ERASE = 0x26, | 185 | MSPRO_CMD_WRITE_DATA = 0x21, |
| 143 | MSPRO_CMD_SET_IBA = 0x46, | 186 | MSPRO_CMD_READ_ATRB = 0x24, |
| 144 | MSPRO_CMD_SET_IBD = 0x47 | 187 | MSPRO_CMD_STOP = 0x25, |
| 145 | /* | 188 | MSPRO_CMD_ERASE = 0x26, |
| 146 | MSPRO_CMD_RESET | 189 | MSPRO_CMD_READ_QUAD = 0x27, |
| 147 | MSPRO_CMD_WAKEUP | 190 | MSPRO_CMD_WRITE_QUAD = 0x28, |
| 148 | MSPRO_CMD_IN_IO_DATA | 191 | MSPRO_CMD_SET_IBD = 0x46, |
| 149 | MSPRO_CMD_OUT_IO_DATA | 192 | MSPRO_CMD_GET_IBD = 0x47, |
| 150 | MSPRO_CMD_READ_IO_ATRB | 193 | MSPRO_CMD_IN_IO_DATA = 0xb0, |
| 151 | MSPRO_CMD_IN_IO_FIFO | 194 | MSPRO_CMD_OUT_IO_DATA = 0xb1, |
| 152 | MSPRO_CMD_OUT_IO_FIFO | 195 | MSPRO_CMD_READ_IO_ATRB = 0xb2, |
| 153 | MSPRO_CMD_IN_IOM | 196 | MSPRO_CMD_IN_IO_FIFO = 0xb3, |
| 154 | MSPRO_CMD_OUT_IOM | 197 | MSPRO_CMD_OUT_IO_FIFO = 0xb4, |
| 155 | */ | 198 | MSPRO_CMD_IN_IOM = 0xb5, |
| 199 | MSPRO_CMD_OUT_IOM = 0xb6, | ||
| 156 | }; | 200 | }; |
| 157 | 201 | ||
| 158 | /*** Driver structures and functions ***/ | 202 | /*** Driver structures and functions ***/ |
| @@ -165,7 +209,8 @@ enum memstick_param { MEMSTICK_POWER = 1, MEMSTICK_INTERFACE }; | |||
| 165 | #define MEMSTICK_POWER_ON 1 | 209 | #define MEMSTICK_POWER_ON 1 |
| 166 | 210 | ||
| 167 | #define MEMSTICK_SERIAL 0 | 211 | #define MEMSTICK_SERIAL 0 |
| 168 | #define MEMSTICK_PARALLEL 1 | 212 | #define MEMSTICK_PAR4 1 |
| 213 | #define MEMSTICK_PAR8 2 | ||
| 169 | 214 | ||
| 170 | struct memstick_host; | 215 | struct memstick_host; |
| 171 | struct memstick_driver; | 216 | struct memstick_driver; |
| @@ -195,11 +240,7 @@ struct memstick_request { | |||
| 195 | unsigned char data_dir:1, | 240 | unsigned char data_dir:1, |
| 196 | need_card_int:1, | 241 | need_card_int:1, |
| 197 | get_int_reg:1, | 242 | get_int_reg:1, |
| 198 | io_type:2; | 243 | long_data:1; |
| 199 | #define MEMSTICK_IO_NONE 0 | ||
| 200 | #define MEMSTICK_IO_VAL 1 | ||
| 201 | #define MEMSTICK_IO_SG 2 | ||
| 202 | |||
| 203 | unsigned char int_reg; | 244 | unsigned char int_reg; |
| 204 | int error; | 245 | int error; |
| 205 | union { | 246 | union { |
| @@ -231,8 +272,9 @@ struct memstick_host { | |||
| 231 | struct mutex lock; | 272 | struct mutex lock; |
| 232 | unsigned int id; | 273 | unsigned int id; |
| 233 | unsigned int caps; | 274 | unsigned int caps; |
| 234 | #define MEMSTICK_CAP_PARALLEL 1 | 275 | #define MEMSTICK_CAP_AUTO_GET_INT 1 |
| 235 | #define MEMSTICK_CAP_AUTO_GET_INT 2 | 276 | #define MEMSTICK_CAP_PAR4 2 |
| 277 | #define MEMSTICK_CAP_PAR8 4 | ||
| 236 | 278 | ||
| 237 | struct work_struct media_checker; | 279 | struct work_struct media_checker; |
| 238 | struct class_device cdev; | 280 | struct class_device cdev; |
| @@ -270,6 +312,8 @@ int memstick_add_host(struct memstick_host *host); | |||
| 270 | void memstick_remove_host(struct memstick_host *host); | 312 | void memstick_remove_host(struct memstick_host *host); |
| 271 | void memstick_free_host(struct memstick_host *host); | 313 | void memstick_free_host(struct memstick_host *host); |
| 272 | void memstick_detect_change(struct memstick_host *host); | 314 | void memstick_detect_change(struct memstick_host *host); |
| 315 | void memstick_suspend_host(struct memstick_host *host); | ||
| 316 | void memstick_resume_host(struct memstick_host *host); | ||
| 273 | 317 | ||
| 274 | void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, | 318 | void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, |
| 275 | struct scatterlist *sg); | 319 | struct scatterlist *sg); |
diff --git a/include/linux/pci.h b/include/linux/pci.h index f3165e7ac431..38eff1947750 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -389,13 +389,13 @@ struct pci_driver { | |||
| 389 | #define to_pci_driver(drv) container_of(drv, struct pci_driver, driver) | 389 | #define to_pci_driver(drv) container_of(drv, struct pci_driver, driver) |
| 390 | 390 | ||
| 391 | /** | 391 | /** |
| 392 | * DECLARE_PCI_DEVICE_TABLE - macro used to describe a pci device table | 392 | * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table |
| 393 | * @_table: device table name | 393 | * @_table: device table name |
| 394 | * | 394 | * |
| 395 | * This macro is used to create a struct pci_device_id array (a device table) | 395 | * This macro is used to create a struct pci_device_id array (a device table) |
| 396 | * in a generic manner. | 396 | * in a generic manner. |
| 397 | */ | 397 | */ |
| 398 | #define DECLARE_PCI_DEVICE_TABLE(_table) \ | 398 | #define DEFINE_PCI_DEVICE_TABLE(_table) \ |
| 399 | const struct pci_device_id _table[] __devinitconst | 399 | const struct pci_device_id _table[] __devinitconst |
| 400 | 400 | ||
| 401 | /** | 401 | /** |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index effdb558a588..70eb3c803d47 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
| @@ -2184,6 +2184,7 @@ | |||
| 2184 | #define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 | 2184 | #define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 |
| 2185 | #define PCI_DEVICE_ID_JMICRON_JMB368 0x2368 | 2185 | #define PCI_DEVICE_ID_JMICRON_JMB368 0x2368 |
| 2186 | #define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 | 2186 | #define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 |
| 2187 | #define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 | ||
| 2187 | 2188 | ||
| 2188 | #define PCI_VENDOR_ID_KORENIX 0x1982 | 2189 | #define PCI_VENDOR_ID_KORENIX 0x1982 |
| 2189 | #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 | 2190 | #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 |
diff --git a/include/linux/tifm.h b/include/linux/tifm.h index da76ed85f595..848c0f392541 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h | |||
| @@ -70,9 +70,9 @@ enum { | |||
| 70 | 70 | ||
| 71 | #define TIFM_FIFO_ENABLE 0x00000001 | 71 | #define TIFM_FIFO_ENABLE 0x00000001 |
| 72 | #define TIFM_FIFO_READY 0x00000001 | 72 | #define TIFM_FIFO_READY 0x00000001 |
| 73 | #define TIFM_FIFO_MORE 0x00000008 | ||
| 73 | #define TIFM_FIFO_INT_SETALL 0x0000ffff | 74 | #define TIFM_FIFO_INT_SETALL 0x0000ffff |
| 74 | #define TIFM_FIFO_INTMASK 0x00000005 | 75 | #define TIFM_FIFO_INTMASK 0x00000005 |
| 75 | #define TIFM_FIFO_SIZE 0x00000200 | ||
| 76 | 76 | ||
| 77 | #define TIFM_DMA_RESET 0x00000002 | 77 | #define TIFM_DMA_RESET 0x00000002 |
| 78 | #define TIFM_DMA_TX 0x00008000 | 78 | #define TIFM_DMA_TX 0x00008000 |
diff --git a/init/Kconfig b/init/Kconfig index 074ac97f55e3..a97924bc5b8d 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -865,38 +865,10 @@ source "block/Kconfig" | |||
| 865 | config PREEMPT_NOTIFIERS | 865 | config PREEMPT_NOTIFIERS |
| 866 | bool | 866 | bool |
| 867 | 867 | ||
| 868 | choice | ||
| 869 | prompt "RCU implementation type:" | ||
| 870 | default CLASSIC_RCU | ||
| 871 | help | ||
| 872 | This allows you to choose either the classic RCU implementation | ||
| 873 | that is designed for best read-side performance on non-realtime | ||
| 874 | systems, or the preemptible RCU implementation for best latency | ||
| 875 | on realtime systems. Note that some kernel preemption modes | ||
| 876 | will restrict your choice. | ||
| 877 | |||
| 878 | Select the default if you are unsure. | ||
| 879 | |||
| 880 | config CLASSIC_RCU | 868 | config CLASSIC_RCU |
| 881 | bool "Classic RCU" | 869 | def_bool !PREEMPT_RCU |
| 882 | help | 870 | help |
| 883 | This option selects the classic RCU implementation that is | 871 | This option selects the classic RCU implementation that is |
| 884 | designed for best read-side performance on non-realtime | 872 | designed for best read-side performance on non-realtime |
| 885 | systems. | 873 | systems. Classic RCU is the default. Note that the |
| 886 | 874 | PREEMPT_RCU symbol is used to select/deselect this option. | |
| 887 | Say Y if you are unsure. | ||
| 888 | |||
| 889 | config PREEMPT_RCU | ||
| 890 | bool "Preemptible RCU" | ||
| 891 | depends on PREEMPT | ||
| 892 | help | ||
| 893 | This option reduces the latency of the kernel by making certain | ||
| 894 | RCU sections preemptible. Normally RCU code is non-preemptible, if | ||
| 895 | this option is selected then read-only RCU sections become | ||
| 896 | preemptible. This helps latency, but may expose bugs due to | ||
| 897 | now-naive assumptions about each RCU read-side critical section | ||
| 898 | remaining on a given CPU through its execution. | ||
| 899 | |||
| 900 | Say N if you are unsure. | ||
| 901 | |||
| 902 | endchoice | ||
| @@ -271,9 +271,10 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma, | |||
| 271 | 271 | ||
| 272 | if (sfd->vm_ops->get_policy) | 272 | if (sfd->vm_ops->get_policy) |
| 273 | pol = sfd->vm_ops->get_policy(vma, addr); | 273 | pol = sfd->vm_ops->get_policy(vma, addr); |
| 274 | else if (vma->vm_policy) | 274 | else if (vma->vm_policy) { |
| 275 | pol = vma->vm_policy; | 275 | pol = vma->vm_policy; |
| 276 | else | 276 | mpol_get(pol); /* get_vma_policy() expects this */ |
| 277 | } else | ||
| 277 | pol = current->mempolicy; | 278 | pol = current->mempolicy; |
| 278 | return pol; | 279 | return pol; |
| 279 | } | 280 | } |
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt index 0669b70fa6a3..9fdba03dc1fc 100644 --- a/kernel/Kconfig.preempt +++ b/kernel/Kconfig.preempt | |||
| @@ -52,8 +52,23 @@ config PREEMPT | |||
| 52 | 52 | ||
| 53 | endchoice | 53 | endchoice |
| 54 | 54 | ||
| 55 | config PREEMPT_RCU | ||
| 56 | bool "Preemptible RCU" | ||
| 57 | depends on PREEMPT | ||
| 58 | default n | ||
| 59 | help | ||
| 60 | This option reduces the latency of the kernel by making certain | ||
| 61 | RCU sections preemptible. Normally RCU code is non-preemptible, if | ||
| 62 | this option is selected then read-only RCU sections become | ||
| 63 | preemptible. This helps latency, but may expose bugs due to | ||
| 64 | now-naive assumptions about each RCU read-side critical section | ||
| 65 | remaining on a given CPU through its execution. | ||
| 66 | |||
| 67 | Say N if you are unsure. | ||
| 68 | |||
| 55 | config RCU_TRACE | 69 | config RCU_TRACE |
| 56 | bool "Enable tracing for RCU - currently stats in debugfs" | 70 | bool "Enable tracing for RCU - currently stats in debugfs" |
| 71 | depends on PREEMPT_RCU | ||
| 57 | select DEBUG_FS | 72 | select DEBUG_FS |
| 58 | default y | 73 | default y |
| 59 | help | 74 | help |
diff --git a/kernel/module.c b/kernel/module.c index be4807fb90e4..5d437bffd8dc 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -2178,10 +2178,20 @@ sys_init_module(void __user *umod, | |||
| 2178 | wake_up(&module_wq); | 2178 | wake_up(&module_wq); |
| 2179 | return ret; | 2179 | return ret; |
| 2180 | } | 2180 | } |
| 2181 | if (ret > 0) { | ||
| 2182 | printk(KERN_WARNING "%s: '%s'->init suspiciously returned %d, " | ||
| 2183 | "it should follow 0/-E convention\n" | ||
| 2184 | KERN_WARNING "%s: loading module anyway...\n", | ||
| 2185 | __func__, mod->name, ret, | ||
| 2186 | __func__); | ||
| 2187 | dump_stack(); | ||
| 2188 | } | ||
| 2181 | 2189 | ||
| 2182 | /* Now it's a first class citizen! */ | 2190 | /* Now it's a first class citizen! Wake up anyone waiting for it. */ |
| 2183 | mutex_lock(&module_mutex); | ||
| 2184 | mod->state = MODULE_STATE_LIVE; | 2191 | mod->state = MODULE_STATE_LIVE; |
| 2192 | wake_up(&module_wq); | ||
| 2193 | |||
| 2194 | mutex_lock(&module_mutex); | ||
| 2185 | /* Drop initial reference. */ | 2195 | /* Drop initial reference. */ |
| 2186 | module_put(mod); | 2196 | module_put(mod); |
| 2187 | unwind_remove_table(mod->unwind_info, 1); | 2197 | unwind_remove_table(mod->unwind_info, 1); |
| @@ -2190,7 +2200,6 @@ sys_init_module(void __user *umod, | |||
| 2190 | mod->init_size = 0; | 2200 | mod->init_size = 0; |
| 2191 | mod->init_text_size = 0; | 2201 | mod->init_text_size = 0; |
| 2192 | mutex_unlock(&module_mutex); | 2202 | mutex_unlock(&module_mutex); |
| 2193 | wake_up(&module_wq); | ||
| 2194 | 2203 | ||
| 2195 | return 0; | 2204 | return 0; |
| 2196 | } | 2205 | } |
diff --git a/mm/filemap.c b/mm/filemap.c index ab98557e228e..df343d1e6345 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
| @@ -1742,21 +1742,27 @@ size_t iov_iter_copy_from_user(struct page *page, | |||
| 1742 | } | 1742 | } |
| 1743 | EXPORT_SYMBOL(iov_iter_copy_from_user); | 1743 | EXPORT_SYMBOL(iov_iter_copy_from_user); |
| 1744 | 1744 | ||
| 1745 | static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes) | 1745 | void iov_iter_advance(struct iov_iter *i, size_t bytes) |
| 1746 | { | 1746 | { |
| 1747 | BUG_ON(i->count < bytes); | ||
| 1748 | |||
| 1747 | if (likely(i->nr_segs == 1)) { | 1749 | if (likely(i->nr_segs == 1)) { |
| 1748 | i->iov_offset += bytes; | 1750 | i->iov_offset += bytes; |
| 1751 | i->count -= bytes; | ||
| 1749 | } else { | 1752 | } else { |
| 1750 | const struct iovec *iov = i->iov; | 1753 | const struct iovec *iov = i->iov; |
| 1751 | size_t base = i->iov_offset; | 1754 | size_t base = i->iov_offset; |
| 1752 | 1755 | ||
| 1753 | /* | 1756 | /* |
| 1754 | * The !iov->iov_len check ensures we skip over unlikely | 1757 | * The !iov->iov_len check ensures we skip over unlikely |
| 1755 | * zero-length segments. | 1758 | * zero-length segments (without overruning the iovec). |
| 1756 | */ | 1759 | */ |
| 1757 | while (bytes || !iov->iov_len) { | 1760 | while (bytes || unlikely(!iov->iov_len && i->count)) { |
| 1758 | int copy = min(bytes, iov->iov_len - base); | 1761 | int copy; |
| 1759 | 1762 | ||
| 1763 | copy = min(bytes, iov->iov_len - base); | ||
| 1764 | BUG_ON(!i->count || i->count < copy); | ||
| 1765 | i->count -= copy; | ||
| 1760 | bytes -= copy; | 1766 | bytes -= copy; |
| 1761 | base += copy; | 1767 | base += copy; |
| 1762 | if (iov->iov_len == base) { | 1768 | if (iov->iov_len == base) { |
| @@ -1768,14 +1774,6 @@ static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes) | |||
| 1768 | i->iov_offset = base; | 1774 | i->iov_offset = base; |
| 1769 | } | 1775 | } |
| 1770 | } | 1776 | } |
| 1771 | |||
| 1772 | void iov_iter_advance(struct iov_iter *i, size_t bytes) | ||
| 1773 | { | ||
| 1774 | BUG_ON(i->count < bytes); | ||
| 1775 | |||
| 1776 | __iov_iter_advance_iov(i, bytes); | ||
| 1777 | i->count -= bytes; | ||
| 1778 | } | ||
| 1779 | EXPORT_SYMBOL(iov_iter_advance); | 1777 | EXPORT_SYMBOL(iov_iter_advance); |
| 1780 | 1778 | ||
| 1781 | /* | 1779 | /* |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index dcacc811e70e..74c1b6b0b37b 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
| @@ -286,6 +286,12 @@ static struct page *alloc_buddy_huge_page(struct vm_area_struct *vma, | |||
| 286 | 286 | ||
| 287 | spin_lock(&hugetlb_lock); | 287 | spin_lock(&hugetlb_lock); |
| 288 | if (page) { | 288 | if (page) { |
| 289 | /* | ||
| 290 | * This page is now managed by the hugetlb allocator and has | ||
| 291 | * no users -- drop the buddy allocator's reference. | ||
| 292 | */ | ||
| 293 | put_page_testzero(page); | ||
| 294 | VM_BUG_ON(page_count(page)); | ||
| 289 | nid = page_to_nid(page); | 295 | nid = page_to_nid(page); |
| 290 | set_compound_page_dtor(page, free_huge_page); | 296 | set_compound_page_dtor(page, free_huge_page); |
| 291 | /* | 297 | /* |
| @@ -369,13 +375,14 @@ free: | |||
| 369 | enqueue_huge_page(page); | 375 | enqueue_huge_page(page); |
| 370 | else { | 376 | else { |
| 371 | /* | 377 | /* |
| 372 | * Decrement the refcount and free the page using its | 378 | * The page has a reference count of zero already, so |
| 373 | * destructor. This must be done with hugetlb_lock | 379 | * call free_huge_page directly instead of using |
| 380 | * put_page. This must be done with hugetlb_lock | ||
| 374 | * unlocked which is safe because free_huge_page takes | 381 | * unlocked which is safe because free_huge_page takes |
| 375 | * hugetlb_lock before deciding how to free the page. | 382 | * hugetlb_lock before deciding how to free the page. |
| 376 | */ | 383 | */ |
| 377 | spin_unlock(&hugetlb_lock); | 384 | spin_unlock(&hugetlb_lock); |
| 378 | put_page(page); | 385 | free_huge_page(page); |
| 379 | spin_lock(&hugetlb_lock); | 386 | spin_lock(&hugetlb_lock); |
| 380 | } | 387 | } |
| 381 | } | 388 | } |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 6c7ba1a63d23..3c3601121509 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -1296,7 +1296,9 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr, | |||
| 1296 | unsigned nid; | 1296 | unsigned nid; |
| 1297 | 1297 | ||
| 1298 | nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT); | 1298 | nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT); |
| 1299 | __mpol_free(pol); /* finished with pol */ | 1299 | if (unlikely(pol != &default_policy && |
| 1300 | pol != current->mempolicy)) | ||
| 1301 | __mpol_free(pol); /* finished with pol */ | ||
| 1300 | return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags); | 1302 | return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags); |
| 1301 | } | 1303 | } |
| 1302 | 1304 | ||
| @@ -1360,6 +1362,9 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr) | |||
| 1360 | unsigned nid; | 1362 | unsigned nid; |
| 1361 | 1363 | ||
| 1362 | nid = interleave_nid(pol, vma, addr, PAGE_SHIFT); | 1364 | nid = interleave_nid(pol, vma, addr, PAGE_SHIFT); |
| 1365 | if (unlikely(pol != &default_policy && | ||
| 1366 | pol != current->mempolicy)) | ||
| 1367 | __mpol_free(pol); /* finished with pol */ | ||
| 1363 | return alloc_page_interleave(gfp, 0, nid); | 1368 | return alloc_page_interleave(gfp, 0, nid); |
| 1364 | } | 1369 | } |
| 1365 | zl = zonelist_policy(gfp, pol); | 1370 | zl = zonelist_policy(gfp, pol); |
