diff options
Diffstat (limited to 'drivers')
148 files changed, 4890 insertions, 1833 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 38aca048e951..66a9d8145562 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -41,6 +41,7 @@ #include <linux/pm_qos_params.h> #include <linux/clockchips.h> #include <linux/cpuidle.h> +#include <linux/irqflags.h> /* * Include the apic definitions for x86 to have the APIC timer related defines diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 5260e9e0df48..989429cfed88 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -347,8 +347,9 @@ static inline int memory_probe_init(void) * section belongs to... */ -static int add_memory_block(unsigned long node_id, struct mem_section *section, - unsigned long state, int phys_device) +static int add_memory_block(int nid, struct mem_section *section, + unsigned long state, int phys_device, + enum mem_add_context context) { struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); int ret = 0; @@ -370,6 +371,10 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section, ret = mem_create_simple_file(mem, phys_device); if (!ret) ret = mem_create_simple_file(mem, removable); + if (!ret) { + if (context == HOTPLUG) + ret = register_mem_sect_under_node(mem, nid); + } return ret; } @@ -382,7 +387,7 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section, * * This could be made generic for all sysdev classes. */ -static struct memory_block *find_memory_block(struct mem_section *section) +struct memory_block *find_memory_block(struct mem_section *section) { struct kobject *kobj; struct sys_device *sysdev; @@ -411,6 +416,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, struct memory_block *mem; mem = find_memory_block(section); + unregister_mem_sect_under_nodes(mem); mem_remove_simple_file(mem, phys_index); mem_remove_simple_file(mem, state); mem_remove_simple_file(mem, phys_device); @@ -424,9 +430,9 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, * need an interface for the VM to add new memory regions, * but without onlining it. */ -int register_new_memory(struct mem_section *section) +int register_new_memory(int nid, struct mem_section *section) { - return add_memory_block(0, section, MEM_OFFLINE, 0); + return add_memory_block(nid, section, MEM_OFFLINE, 0, HOTPLUG); } int unregister_memory_section(struct mem_section *section) @@ -458,7 +464,8 @@ int __init memory_dev_init(void) for (i = 0; i < NR_MEM_SECTIONS; i++) { if (!present_section_nr(i)) continue; - err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); + err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, + 0, BOOT); if (!ret) ret = err; } diff --git a/drivers/base/node.c b/drivers/base/node.c index 91636cd8b6c9..43fa90b837ee 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> +#include <linux/memory.h> #include <linux/node.h> #include <linux/hugetlb.h> #include <linux/cpumask.h> @@ -248,6 +249,105 @@ int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) return 0; } +#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE +#define page_initialized(page) (page->lru.next) + +static int get_nid_for_pfn(unsigned long pfn) +{ + struct page *page; + + if (!pfn_valid_within(pfn)) + return -1; + page = pfn_to_page(pfn); + if (!page_initialized(page)) + return -1; + return pfn_to_nid(pfn); +} + +/* register memory section under specified node if it spans that node */ +int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) +{ + unsigned long pfn, sect_start_pfn, sect_end_pfn; + + if (!mem_blk) + return -EFAULT; + if (!node_online(nid)) + return 0; + sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); + sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; + for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { + int page_nid; + + page_nid = get_nid_for_pfn(pfn); + if (page_nid < 0) + continue; + if (page_nid != nid) + continue; + return sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj, + &mem_blk->sysdev.kobj, + kobject_name(&mem_blk->sysdev.kobj)); + } + /* mem section does not span the specified node */ + return 0; +} + +/* unregister memory section under all nodes that it spans */ +int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) +{ + nodemask_t unlinked_nodes; + unsigned long pfn, sect_start_pfn, sect_end_pfn; + + if (!mem_blk) + return -EFAULT; + nodes_clear(unlinked_nodes); + sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); + sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; + for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { + unsigned int nid; + + nid = get_nid_for_pfn(pfn); + if (nid < 0) + continue; + if (!node_online(nid)) + continue; + if (node_test_and_set(nid, unlinked_nodes)) + continue; + sysfs_remove_link(&node_devices[nid].sysdev.kobj, + kobject_name(&mem_blk->sysdev.kobj)); + } + return 0; +} + +static int link_mem_sections(int nid) +{ + unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; + unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; + unsigned long pfn; + int err = 0; + + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + unsigned long section_nr = pfn_to_section_nr(pfn); + struct mem_section *mem_sect; + struct memory_block *mem_blk; + int ret; + + if (!present_section_nr(section_nr)) + continue; + mem_sect = __nr_to_section(section_nr); + mem_blk = find_memory_block(mem_sect); + ret = register_mem_sect_under_node(mem_blk, nid); + if (!err) + err = ret; + + /* discard ref obtained in find_memory_block() */ + kobject_put(&mem_blk->sysdev.kobj); + } + return err; +} +#else +static int link_mem_sections(int nid) { return 0; } +#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ + int register_one_node(int nid) { int error = 0; @@ -267,6 +367,9 @@ int register_one_node(int nid) if (cpu_to_node(cpu) == nid) register_cpu_under_node(cpu, nid); } + + /* link memory sections under this node */ + error = link_mem_sections(nid); } return error; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 1697043119bd..35914b6e1d2a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -841,7 +841,7 @@ config JS_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 + depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 && !BLACKFIN ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index 4246b8e36cb3..45d3e80156d4 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -554,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) __get_user(fontpos, &list->fontpos); if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0) err = err1; - list++; + list++; } if (con_unify_unimap(vc, p)) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 6431f6921a67..3586b3b3df3f 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -425,9 +425,6 @@ static ssize_t read_oldmem(struct file *file, char __user *buf, } #endif -extern long vread(char *buf, char *addr, unsigned long count); -extern long vwrite(char *buf, char *addr, unsigned long count); - #ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. diff --git a/drivers/char/random.c b/drivers/char/random.c index c7afc068c28d..7c13581ca9cd 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -407,7 +407,7 @@ struct entropy_store { /* read-write data: */ spinlock_t lock; unsigned add_ptr; - int entropy_count; /* Must at no time exceed ->POOLBITS! */ + int entropy_count; int input_rotate; }; @@ -767,11 +767,10 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, { unsigned long flags; - BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); - /* Hold lock while accounting */ spin_lock_irqsave(&r->lock, flags); + BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); DEBUG_ENT("trying to extract %d bits from %s\n", nbytes * 8, r->name); diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 94966edfb44d..d41b9f6f7903 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -82,7 +82,7 @@ static void sysrq_handle_loglevel(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_loglevel_op = { .handler = sysrq_handle_loglevel, - .help_msg = "loglevel0-8", + .help_msg = "loglevel(0-9)", .action_msg = "Changing Loglevel", .enable_mask = SYSRQ_ENABLE_LOG, }; @@ -233,7 +233,7 @@ static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) static struct sysrq_key_op sysrq_showallcpus_op = { .handler = sysrq_handle_showallcpus, - .help_msg = "aLlcpus", + .help_msg = "show-backtrace-all-active-cpus(L)", .action_msg = "Show backtrace of all active CPUs", .enable_mask = SYSRQ_ENABLE_DUMP, }; @@ -247,7 +247,7 @@ static void sysrq_handle_showregs(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, - .help_msg = "showPc", + .help_msg = "show-registers(P)", .action_msg = "Show Regs", .enable_mask = SYSRQ_ENABLE_DUMP, }; @@ -258,7 +258,7 @@ static void sysrq_handle_showstate(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_showstate_op = { .handler = sysrq_handle_showstate, - .help_msg = "showTasks", + .help_msg = "show-task-states(T)", .action_msg = "Show State", .enable_mask = SYSRQ_ENABLE_DUMP, }; @@ -269,7 +269,7 @@ static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_showstate_blocked_op = { .handler = sysrq_handle_showstate_blocked, - .help_msg = "shoW-blocked-tasks", + .help_msg = "show-blocked-tasks(W)", .action_msg = "Show Blocked State", .enable_mask = SYSRQ_ENABLE_DUMP, }; @@ -297,7 +297,7 @@ static void sysrq_handle_showmem(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_showmem_op = { .handler = sysrq_handle_showmem, - .help_msg = "showMem", + .help_msg = "show-memory-usage(M)", .action_msg = "Show Memory", .enable_mask = SYSRQ_ENABLE_DUMP, }; @@ -323,7 +323,7 @@ static void sysrq_handle_term(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_term_op = { .handler = sysrq_handle_term, - .help_msg = "tErm", + .help_msg = "terminate-all-tasks(E)", .action_msg = "Terminate All Tasks", .enable_mask = SYSRQ_ENABLE_SIGNAL, }; @@ -341,7 +341,7 @@ static void sysrq_handle_moom(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_moom_op = { .handler = sysrq_handle_moom, - .help_msg = "Full", + .help_msg = "memory-full-oom-kill(F)", .action_msg = "Manual OOM execution", .enable_mask = SYSRQ_ENABLE_SIGNAL, }; @@ -353,7 +353,7 @@ static void sysrq_handle_kill(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_kill_op = { .handler = sysrq_handle_kill, - .help_msg = "kIll", + .help_msg = "kill-all-tasks(I)", .action_msg = "Kill All Tasks", .enable_mask = SYSRQ_ENABLE_SIGNAL, }; @@ -364,7 +364,7 @@ static void sysrq_handle_unrt(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_unrt_op = { .handler = sysrq_handle_unrt, - .help_msg = "Nice", + .help_msg = "nice-all-RT-tasks(N)", .action_msg = "Nice All RT Tasks", .enable_mask = SYSRQ_ENABLE_RTNICE, }; diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index e2667a8c2997..eee47fd16d79 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -109,6 +109,13 @@ config EDAC_X38 Support for error detection and correction on the Intel X38 server chipsets. +config EDAC_I5400 + tristate "Intel 5400 (Seaburg) chipsets" + depends on EDAC_MM_EDAC && PCI && X86 + help + Support for error detection and correction the Intel + i5400 MCH chipset (Seaburg). + config EDAC_I82860 tristate "Intel 82860" depends on EDAC_MM_EDAC && PCI && X86_32 diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 62c2d9bad8dc..b75196927de3 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -20,6 +20,7 @@ endif obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o obj-$(CONFIG_EDAC_I5100) += i5100_edac.o +obj-$(CONFIG_EDAC_I5400) += i5400_edac.o obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o obj-$(CONFIG_EDAC_E752X) += e752x_edac.o obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 4041e9143283..ca9113e1c106 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -333,7 +333,7 @@ static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev) fail0: edac_printk(KERN_WARNING, EDAC_MC, "%s (%s) %s %s already assigned %d\n", - rover->dev->bus_id, edac_dev_name(rover), + dev_name(rover->dev), edac_dev_name(rover), rover->mod_name, rover->ctl_name, rover->dev_idx); return 1; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index d110392d48f4..25d66940b4fa 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -401,7 +401,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci) fail0: edac_printk(KERN_WARNING, EDAC_MC, - "%s (%s) %s %s already assigned %d\n", p->dev->bus_id, + "%s (%s) %s %s already assigned %d\n", dev_name(p->dev), edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx); return 1; diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 22ec9d5d4312..5d3c8083a40e 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -150,7 +150,7 @@ static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci) fail0: edac_printk(KERN_WARNING, EDAC_PCI, "%s (%s) %s %s already assigned %d\n", - rover->dev->bus_id, edac_dev_name(rover), + dev_name(rover->dev), edac_dev_name(rover), rover->mod_name, rover->ctl_name, rover->pci_idx); return 1; diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 5c153dccc95e..422728cfe994 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -569,7 +569,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) local_irq_restore(flags); - debugf4("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id); + debugf4("PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev)); /* check the status reg for errors on boards NOT marked as broken * if broken, we cannot trust any of the status bits @@ -600,13 +600,13 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) } - debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id); + debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev_name(&dev->dev)); if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* On bridges, need to examine secondary status register */ status = get_pci_parity_status(dev, 1); - debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id); + debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev_name(&dev->dev)); /* check the secondary status reg for errors, * on NOT broken boards diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c new file mode 100644 index 000000000000..b08b6d8e2dc7 --- /dev/null +++ b/drivers/edac/i5400_edac.c @@ -0,0 +1,1476 @@ +/* + * Intel 5400 class Memory Controllers kernel module (Seaburg) + * + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Copyright (c) 2008 by: + * Ben Woodard <woodard@redhat.com> + * Mauro Carvalho Chehab <mchehab@redhat.com> + * + * Red Hat Inc. http://www.redhat.com + * + * Forked and adapted from the i5000_edac driver which was + * written by Douglas Thompson Linux Networx <norsk5@xmission.com> + * + * This module is based on the following document: + * + * Intel 5400 Chipset Memory Controller Hub (MCH) - Datasheet + * http://developer.intel.com/design/chipsets/datashts/313070.htm + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/slab.h> +#include <linux/edac.h> +#include <linux/mmzone.h> + +#include "edac_core.h" + +/* + * Alter this version for the I5400 module when modifications are made + */ +#define I5400_REVISION " Ver: 1.0.0 " __DATE__ + +#define EDAC_MOD_STR "i5400_edac" + +#define i5400_printk(level, fmt, arg...) \ + edac_printk(level, "i5400", fmt, ##arg) + +#define i5400_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "i5400", fmt, ##arg) + +/* Limits for i5400 */ +#define NUM_MTRS_PER_BRANCH 4 +#define CHANNELS_PER_BRANCH 2 +#define MAX_CHANNELS 4 +#define MAX_DIMMS (MAX_CHANNELS * 4) /* Up to 4 DIMM's per channel */ +#define MAX_CSROWS (MAX_DIMMS * 2) /* max possible csrows per channel */ + +/* Device 16, + * Function 0: System Address + * Function 1: Memory Branch Map, Control, Errors Register + * Function 2: FSB Error Registers + * + * All 3 functions of Device 16 (0,1,2) share the SAME DID and + * uses PCI_DEVICE_ID_INTEL_5400_ERR for device 16 (0,1,2), + * PCI_DEVICE_ID_INTEL_5400_FBD0 and PCI_DEVICE_ID_INTEL_5400_FBD1 + * for device 21 (0,1). + */ + + /* OFFSETS for Function 0 */ +#define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */ +#define MAXCH 0x56 /* Max Channel Number */ +#define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */ + + /* OFFSETS for Function 1 */ +#define TOLM 0x6C +#define REDMEMB 0x7C +#define REC_ECC_LOCATOR_ODD(x) ((x) & 0x3fe00) /* bits [17:9] indicate ODD, [8:0] indicate EVEN */ +#define MIR0 0x80 +#define MIR1 0x84 +#define AMIR0 0x8c +#define AMIR1 0x90 + + /* Fatal error registers */ +#define FERR_FAT_FBD 0x98 /* also called as FERR_FAT_FB_DIMM at datasheet */ +#define FERR_FAT_FBDCHAN (3<<28) /* channel index where the highest-order error occurred */ + +#define NERR_FAT_FBD 0x9c +#define FERR_NF_FBD 0xa0 /* also called as FERR_NFAT_FB_DIMM at datasheet */ + + /* Non-fatal error register */ +#define NERR_NF_FBD 0xa4 + + /* Enable error mask */ +#define EMASK_FBD 0xa8 + +#define ERR0_FBD 0xac +#define ERR1_FBD 0xb0 +#define ERR2_FBD 0xb4 +#define MCERR_FBD 0xb8 + + /* No OFFSETS for Device 16 Function 2 */ + +/* + * Device 21, + * Function 0: Memory Map Branch 0 + * + * Device 22, + * Function 0: Memory Map Branch 1 + */ + + /* OFFSETS for Function 0 */ +#define AMBPRESENT_0 0x64 +#define AMBPRESENT_1 0x66 +#define MTR0 0x80 +#define MTR1 0x82 +#define MTR2 0x84 +#define MTR3 0x86 + + /* OFFSETS for Function 1 */ +#define NRECFGLOG 0x74 +#define RECFGLOG 0x78 +#define NRECMEMA 0xbe +#define NRECMEMB 0xc0 +#define NRECFB_DIMMA 0xc4 +#define NRECFB_DIMMB 0xc8 +#define NRECFB_DIMMC 0xcc +#define NRECFB_DIMMD 0xd0 +#define NRECFB_DIMME 0xd4 +#define NRECFB_DIMMF 0xd8 +#define REDMEMA 0xdC +#define RECMEMA 0xf0 +#define RECMEMB 0xf4 +#define RECFB_DIMMA 0xf8 +#define RECFB_DIMMB 0xec +#define RECFB_DIMMC 0xf0 +#define RECFB_DIMMD 0xf4 +#define RECFB_DIMME 0xf8 +#define RECFB_DIMMF 0xfC + +/* + * Error indicator bits and masks + * Error masks are according with Table 5-17 of i5400 datasheet + */ + +enum error_mask { + EMASK_M1 = 1<<0, /* Memory Write error on non-redundant retry */ + EMASK_M2 = 1<<1, /* Memory or FB-DIMM configuration CRC read error */ + EMASK_M3 = 1<<2, /* Reserved */ + EMASK_M4 = 1<<3, /* Uncorrectable Data ECC on Replay */ + EMASK_M5 = 1<<4, /* Aliased Uncorrectable Non-Mirrored Demand Data ECC */ + EMASK_M6 = 1<<5, /* Unsupported on i5400 */ + EMASK_M7 = 1<<6, /* Aliased Uncorrectable Resilver- or Spare-Copy Data ECC */ + EMASK_M8 = 1<<7, /* Aliased Uncorrectable Patrol Data ECC */ + EMASK_M9 = 1<<8, /* Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC */ + EMASK_M10 = 1<<9, /* Unsupported on i5400 */ + EMASK_M11 = 1<<10, /* Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC */ + EMASK_M12 = 1<<11, /* Non-Aliased Uncorrectable Patrol Data ECC */ + EMASK_M13 = 1<<12, /* Memory Write error on first attempt */ + EMASK_M14 = 1<<13, /* FB-DIMM Configuration Write error on first attempt */ + EMASK_M15 = 1<<14, /* Memory or FB-DIMM configuration CRC read error */ + EMASK_M16 = 1<<15, /* Channel Failed-Over Occurred */ + EMASK_M17 = 1<<16, /* Correctable Non-Mirrored Demand Data ECC */ + EMASK_M18 = 1<<17, /* Unsupported on i5400 */ + EMASK_M19 = 1<<18, /* Correctable Resilver- or Spare-Copy Data ECC */ + EMASK_M20 = 1<<19, /* Correctable Patrol Data ECC */ + EMASK_M21 = 1<<20, /* FB-DIMM Northbound parity error on FB-DIMM Sync Status */ + EMASK_M22 = 1<<21, /* SPD protocol Error */ + EMASK_M23 = 1<<22, /* Non-Redundant Fast Reset Timeout */ + EMASK_M24 = 1<<23, /* Refresh error */ + EMASK_M25 = 1<<24, /* Memory Write error on redundant retry */ + EMASK_M26 = 1<<25, /* Redundant Fast Reset Timeout */ + EMASK_M27 = 1<<26, /* Correctable Counter Threshold Exceeded */ + EMASK_M28 = 1<<27, /* DIMM-Spare Copy Completed */ + EMASK_M29 = 1<<28, /* DIMM-Isolation Completed */ +}; + +/* + * Names to translate bit error into something useful + */ +static const char *error_name[] = { + [0] = "Memory Write error on non-redundant retry", + [1] = "Memory or FB-DIMM configuration CRC read error", + /* Reserved */ + [3] = "Uncorrectable Data ECC on Replay", + [4] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", + /* M6 Unsupported on i5400 */ + [6] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", + [7] = "Aliased Uncorrectable Patrol Data ECC", + [8] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC", + /* M10 Unsupported on i5400 */ + [10] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", + [11] = "Non-Aliased Uncorrectable Patrol Data ECC", + [12] = "Memory Write error on first attempt", + [13] = "FB-DIMM Configuration Write error on first attempt", + [14] = "Memory or FB-DIMM configuration CRC read error", + [15] = "Channel Failed-Over Occurred", + [16] = "Correctable Non-Mirrored Demand Data ECC", + /* M18 Unsupported on i5400 */ + [18] = "Correctable Resilver- or Spare-Copy Data ECC", + [19] = "Correctable Patrol Data ECC", + [20] = "FB-DIMM Northbound parity error on FB-DIMM Sync Status", + [21] = "SPD protocol Error", + [22] = "Non-Redundant Fast Reset Timeout", + [23] = "Refresh error", + [24] = "Memory Write error on redundant retry", + [25] = "Redundant Fast Reset Timeout", + [26] = "Correctable Counter Threshold Exceeded", + [27] = "DIMM-Spare Copy Completed", + [28] = "DIMM-Isolation Completed", +}; + +/* Fatal errors */ +#define ERROR_FAT_MASK (EMASK_M1 | \ + EMASK_M2 | \ + EMASK_M23) + +/* Correctable errors */ +#define ERROR_NF_CORRECTABLE (EMASK_M27 | \ + EMASK_M20 | \ + EMASK_M19 | \ + EMASK_M18 | \ + EMASK_M17 | \ + EMASK_M16) +#define ERROR_NF_DIMM_SPARE (EMASK_M29 | \ + EMASK_M28) +#define ERROR_NF_SPD_PROTOCOL (EMASK_M22) +#define ERROR_NF_NORTH_CRC (EMASK_M21) + +/* Recoverable errors */ +#define ERROR_NF_RECOVERABLE (EMASK_M26 | \ + EMASK_M25 | \ + EMASK_M24 | \ + EMASK_M15 | \ + EMASK_M14 | \ + EMASK_M13 | \ + EMASK_M12 | \ + EMASK_M11 | \ + EMASK_M9 | \ + EMASK_M8 | \ + EMASK_M7 | \ + EMASK_M5) + +/* uncorrectable errors */ +#define ERROR_NF_UNCORRECTABLE (EMASK_M4) + +/* mask to all non-fatal errors */ +#define ERROR_NF_MASK (ERROR_NF_CORRECTABLE | \ + ERROR_NF_UNCORRECTABLE | \ + ERROR_NF_RECOVERABLE | \ + ERROR_NF_DIMM_SPARE | \ + ERROR_NF_SPD_PROTOCOL | \ + ERROR_NF_NORTH_CRC) + +/* + * Define error masks for the several registers + */ + +/* Enable all fatal and non fatal errors */ +#define ENABLE_EMASK_ALL (ERROR_FAT_MASK | ERROR_NF_MASK) + +/* mask for fatal error registers */ +#define FERR_FAT_MASK ERROR_FAT_MASK + +/* masks for non-fatal error register */ +static inline int to_nf_mask(unsigned int mask) +{ + return (mask & EMASK_M29) | (mask >> 3); +}; + +static inline int from_nf_ferr(unsigned int mask) +{ + return (mask & EMASK_M29) | /* Bit 28 */ + (mask & ((1 << 28) - 1) << 3); /* Bits 0 to 27 */ +}; + +#define FERR_NF_MASK to_nf_mask(ERROR_NF_MASK) +#define FERR_NF_CORRECTABLE to_nf_mask(ERROR_NF_CORRECTABLE) +#define FERR_NF_DIMM_SPARE to_nf_mask(ERROR_NF_DIMM_SPARE) +#define FERR_NF_SPD_PROTOCOL to_nf_mask(ERROR_NF_SPD_PROTOCOL) +#define FERR_NF_NORTH_CRC to_nf_mask(ERROR_NF_NORTH_CRC) +#define FERR_NF_RECOVERABLE to_nf_mask(ERROR_NF_RECOVERABLE) +#define FERR_NF_UNCORRECTABLE to_nf_mask(ERROR_NF_UNCORRECTABLE) + +/* Defines to extract the vaious fields from the + * MTRx - Memory Technology Registers + */ +#define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 10)) +#define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 9)) +#define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 8)) ? 8 : 4) +#define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 6)) ? 8 : 4) +#define MTR_DRAM_BANKS_ADDR_BITS(mtr) ((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2) +#define MTR_DIMM_RANK(mtr) (((mtr) >> 5) & 0x1) +#define MTR_DIMM_RANK_ADDR_BITS(mtr) (MTR_DIMM_RANK(mtr) ? 2 : 1) +#define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) +#define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) +#define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) +#define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) + +/* This applies to FERR_NF_FB-DIMM as well as FERR_FAT_FB-DIMM */ +static inline int extract_fbdchan_indx(u32 x) +{ + return (x>>28) & 0x3; +} + +#ifdef CONFIG_EDAC_DEBUG +/* MTR NUMROW */ +static const char *numrow_toString[] = { + "8,192 - 13 rows", + "16,384 - 14 rows", + "32,768 - 15 rows", + "65,536 - 16 rows" +}; + +/* MTR NUMCOL */ +static const char *numcol_toString[] = { + "1,024 - 10 columns", + "2,048 - 11 columns", + "4,096 - 12 columns", + "reserved" +}; +#endif + +/* Device name and register DID (Device ID) */ +struct i5400_dev_info { + const char *ctl_name; /* name for this device */ + u16 fsb_mapping_errors; /* DID for the branchmap,control */ +}; + +/* Table of devices attributes supported by this driver */ +static const struct i5400_dev_info i5400_devs[] = { + { + .ctl_name = "I5400", + .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_5400_ERR, + }, +}; + +struct i5400_dimm_info { + int megabytes; /* size, 0 means not present */ + int dual_rank; +}; + +/* driver private data structure */ +struct i5400_pvt { + struct pci_dev *system_address; /* 16.0 */ + struct pci_dev *branchmap_werrors; /* 16.1 */ + struct pci_dev *fsb_error_regs; /* 16.2 */ + struct pci_dev *branch_0; /* 21.0 */ + struct pci_dev *branch_1; /* 22.0 */ + + u16 tolm; /* top of low memory */ + u64 ambase; /* AMB BAR */ + + u16 mir0, mir1; + + u16 b0_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */ + u16 b0_ambpresent0; /* Branch 0, Channel 0 */ + u16 b0_ambpresent1; /* Brnach 0, Channel 1 */ + + u16 b1_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */ + u16 b1_ambpresent0; /* Branch 1, Channel 8 */ + u16 b1_ambpresent1; /* Branch 1, Channel 1 */ + + /* DIMM information matrix, allocating architecture maximums */ + struct i5400_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS]; + + /* Actual values for this controller */ + int maxch; /* Max channels */ + int maxdimmperch; /* Max DIMMs per channel */ +}; + +/* I5400 MCH error information retrieved from Hardware */ +struct i5400_error_info { + /* These registers are always read from the MC */ + u32 ferr_fat_fbd; /* First Errors Fatal */ + u32 nerr_fat_fbd; /* Next Errors Fatal */ + u32 ferr_nf_fbd; /* First Errors Non-Fatal */ + u32 nerr_nf_fbd; /* Next Errors Non-Fatal */ + + /* These registers are input ONLY if there was a Recoverable Error */ + u32 redmemb; /* Recoverable Mem Data Error log B */ + u16 recmema; /* Recoverable Mem Error log A */ + u32 recmemb; /* Recoverable Mem Error log B */ + + /* These registers are input ONLY if there was a Non-Rec Error */ + u16 nrecmema; /* Non-Recoverable Mem log A */ + u16 nrecmemb; /* Non-Recoverable Mem log B */ + +}; + +/* note that nrec_rdwr changed from NRECMEMA to NRECMEMB between the 5000 and + 5400 better to use an inline function than a macro in this case */ +static inline int nrec_bank(struct i5400_error_info *info) +{ + return ((info->nrecmema) >> 12) & 0x7; +} +static inline int nrec_rank(struct i5400_error_info *info) +{ + return ((info->nrecmema) >> 8) & 0xf; +} +static inline int nrec_buf_id(struct i5400_error_info *info) +{ + return ((info->nrecmema)) & 0xff; +} +static inline int nrec_rdwr(struct i5400_error_info *info) +{ + return (info->nrecmemb) >> 31; +} +/* This applies to both NREC and REC string so it can be used with nrec_rdwr + and rec_rdwr */ +static inline const char *rdwr_str(int rdwr) +{ + return rdwr ? "Write" : "Read"; +} +static inline int nrec_cas(struct i5400_error_info *info) +{ + return ((info->nrecmemb) >> 16) & 0x1fff; +} +static inline int nrec_ras(struct i5400_error_info *info) +{ + return (info->nrecmemb) & 0xffff; +} +static inline int rec_bank(struct i5400_error_info *info) +{ + return ((info->recmema) >> 12) & 0x7; +} +static inline int rec_rank(struct i5400_error_info *info) +{ + return ((info->recmema) >> 8) & 0xf; +} +static inline int rec_rdwr(struct i5400_error_info *info) +{ + return (info->recmemb) >> 31; +} +static inline int rec_cas(struct i5400_error_info *info) +{ + return ((info->recmemb) >> 16) & 0x1fff; +} +static inline int rec_ras(struct i5400_error_info *info) +{ + return (info->recmemb) & 0xffff; +} + +static struct edac_pci_ctl_info *i5400_pci; + +/* + * i5400_get_error_info Retrieve the hardware error information from + * the hardware and cache it in the 'info' + * structure + */ +static void i5400_get_error_info(struct mem_ctl_info *mci, + struct i5400_error_info *info) +{ + struct i5400_pvt *pvt; + u32 value; + + pvt = mci->pvt_info; + + /* read in the 1st FATAL error register */ + pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value); + + /* Mask only the bits that the doc says are valid + */ + value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK); + + /* If there is an error, then read in the + NEXT FATAL error register and the Memory Error Log Register A + */ + if (value & FERR_FAT_MASK) { + info->ferr_fat_fbd = value; + + /* harvest the various error data we need */ + pci_read_config_dword(pvt->branchmap_werrors, + NERR_FAT_FBD, &info->nerr_fat_fbd); + pci_read_config_word(pvt->branchmap_werrors, + NRECMEMA, &info->nrecmema); + pci_read_config_word(pvt->branchmap_werrors, + NRECMEMB, &info->nrecmemb); + + /* Clear the error bits, by writing them back */ + pci_write_config_dword(pvt->branchmap_werrors, + FERR_FAT_FBD, value); + } else { + info->ferr_fat_fbd = 0; + info->nerr_fat_fbd = 0; + info->nrecmema = 0; + info->nrecmemb = 0; + } + + /* read in the 1st NON-FATAL error register */ + pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value); + + /* If there is an error, then read in the 1st NON-FATAL error + * register as well */ + if (value & FERR_NF_MASK) { + info->ferr_nf_fbd = value; + + /* harvest the various error data we need */ + pci_read_config_dword(pvt->branchmap_werrors, + NERR_NF_FBD, &info->nerr_nf_fbd); + pci_read_config_word(pvt->branchmap_werrors, + RECMEMA, &info->recmema); + pci_read_config_dword(pvt->branchmap_werrors, + RECMEMB, &info->recmemb); + pci_read_config_dword(pvt->branchmap_werrors, + REDMEMB, &info->redmemb); + + /* Clear the error bits, by writing them back */ + pci_write_config_dword(pvt->branchmap_werrors, + FERR_NF_FBD, value); + } else { + info->ferr_nf_fbd = 0; + info->nerr_nf_fbd = 0; + info->recmema = 0; + info->recmemb = 0; + info->redmemb = 0; + } +} + +/* + * i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci, + * struct i5400_error_info *info, + * int handle_errors); + * + * handle the Intel FATAL and unrecoverable errors, if any + */ +static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci, + struct i5400_error_info *info, + unsigned long allErrors) +{ + char msg[EDAC_MC_LABEL_LEN + 1 + 90 + 80]; + int branch; + int channel; + int bank; + int buf_id; + int rank; + int rdwr; + int ras, cas; + int errnum; + char *type = NULL; + + if (!allErrors) + return; /* if no error, return now */ + + if (allErrors & ERROR_FAT_MASK) + type = "FATAL"; + else if (allErrors & FERR_NF_UNCORRECTABLE) + type = "NON-FATAL uncorrected"; + else + type = "NON-FATAL recoverable"; + + /* ONLY ONE of the possible error bits will be set, as per the docs */ + + branch = extract_fbdchan_indx(info->ferr_fat_fbd); + channel = branch; + + /* Use the NON-Recoverable macros to extract data */ + bank = nrec_bank(info); + rank = nrec_rank(info); + buf_id = nrec_buf_id(info); + rdwr = nrec_rdwr(info); + ras = nrec_ras(info); + cas = nrec_cas(info); + + debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d " + "DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n", + rank, channel, channel + 1, branch >> 1, bank, + buf_id, rdwr_str(rdwr), ras, cas); + + /* Only 1 bit will be on */ + errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); + + /* Form out message */ + snprintf(msg, sizeof(msg), + "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " + "RAS=%d CAS=%d %s Err=0x%lx (%s))", + type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, + type, allErrors, error_name[errnum]); + + /* Call the helper to output message */ + edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); +} + +/* + * i5400_process_fatal_error_info(struct mem_ctl_info *mci, + * struct i5400_error_info *info, + * int handle_errors); + * + * handle the Intel NON-FATAL errors, if any + */ +static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci, + struct i5400_error_info *info) +{ + char msg[EDAC_MC_LABEL_LEN + 1 + 90 + 80]; + unsigned long allErrors; + int branch; + int channel; + int bank; + int rank; + int rdwr; + int ras, cas; + int errnum; + + /* mask off the Error bits that are possible */ + allErrors = from_nf_ferr(info->ferr_nf_fbd & FERR_NF_MASK); + if (!allErrors) + return; /* if no error, return now */ + + /* ONLY ONE of the possible error bits will be set, as per the docs */ + + if (allErrors & (ERROR_NF_UNCORRECTABLE | ERROR_NF_RECOVERABLE)) { + i5400_proccess_non_recoverable_info(mci, info, allErrors); + return; + } + + /* Correctable errors */ + if (allErrors & ERROR_NF_CORRECTABLE) { + debugf0("\tCorrected bits= 0x%lx\n", allErrors); + + branch = extract_fbdchan_indx(info->ferr_nf_fbd); + + channel = 0; + if (REC_ECC_LOCATOR_ODD(info->redmemb)) + channel = 1; + + /* Convert channel to be based from zero, instead of + * from branch base of 0 */ + channel += branch; + + bank = rec_bank(info); + rank = rec_rank(info); + rdwr = rec_rdwr(info); + ras = rec_ras(info); + cas = rec_cas(info); + + /* Only 1 bit will be on */ + errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); + + debugf0("\t\tCSROW= %d Channel= %d (Branch %d " + "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", + rank, channel, branch >> 1, bank, + rdwr_str(rdwr), ras, cas); + + /* Form out message */ + snprintf(msg, sizeof(msg), + "Corrected error (Branch=%d DRAM-Bank=%d RDWR=%s " + "RAS=%d CAS=%d, CE Err=0x%lx (%s))", + branch >> 1, bank, rdwr_str(rdwr), ras, cas, + allErrors, error_name[errnum]); + + /* Call the helper to output message */ + edac_mc_handle_fbd_ce(mci, rank, channel, msg); + + return; + } + + /* Miscelaneous errors */ + errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); + + branch = extract_fbdchan_indx(info->ferr_nf_fbd); + + i5400_mc_printk(mci, KERN_EMERG, + "Non-Fatal misc error (Branch=%d Err=%#lx (%s))", + branch >> 1, allErrors, error_name[errnum]); +} + +/* + * i5400_process_error_info Process the error info that is + * in the 'info' structure, previously retrieved from hardware + */ +static void i5400_process_error_info(struct mem_ctl_info *mci, + struct i5400_error_info *info) +{ u32 allErrors; + + /* First handle any fatal errors that occurred */ + allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK); + i5400_proccess_non_recoverable_info(mci, info, allErrors); + + /* now handle any non-fatal errors that occurred */ + i5400_process_nonfatal_error_info(mci, info); +} + +/* + * i5400_clear_error Retrieve any error from the hardware + * but do NOT process that error. + * Used for 'clearing' out of previous errors + * Called by the Core module. + */ +static void i5400_clear_error(struct mem_ctl_info *mci) +{ + struct i5400_error_info info; + + i5400_get_error_info(mci, &info); +} + +/* + * i5400_check_error Retrieve and process errors reported by the + * hardware. Called by the Core module. + */ +static void i5400_check_error(struct mem_ctl_info *mci) +{ + struct i5400_error_info info; + debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + i5400_get_error_info(mci, &info); + i5400_process_error_info(mci, &info); +} + +/* + * i5400_put_devices 'put' all the devices that we have + * reserved via 'get' + */ +static void i5400_put_devices(struct mem_ctl_info *mci) +{ + struct i5400_pvt *pvt; + + pvt = mci->pvt_info; + + /* Decrement usage count for devices */ + pci_dev_put(pvt->branch_1); + pci_dev_put(pvt->branch_0); + pci_dev_put(pvt->fsb_error_regs); + pci_dev_put(pvt->branchmap_werrors); +} + +/* + * i5400_get_devices Find and perform 'get' operation on the MCH's + * device/functions we want to reference for this driver + * + * Need to 'get' device 16 func 1 and func 2 + */ +static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx) +{ + struct i5400_pvt *pvt; + struct pci_dev *pdev; + + pvt = mci->pvt_info; + pvt->branchmap_werrors = NULL; + pvt->fsb_error_regs = NULL; + pvt->branch_0 = NULL; + pvt->branch_1 = NULL; + + /* Attempt to 'get' the MCH register we want */ + pdev = NULL; + while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_5400_ERR, pdev); + if (!pdev) { + /* End of list, leave */ + i5400_printk(KERN_ERR, + "'system address,Process Bus' " + "device not found:" + "vendor 0x%x device 0x%x ERR funcs " + "(broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_5400_ERR); + goto error; + } + + /* Store device 16 funcs 1 and 2 */ + switch (PCI_FUNC(pdev->devfn)) { + case 1: + pvt->branchmap_werrors = pdev; + break; + case 2: + pvt->fsb_error_regs = pdev; + break; + } + } + + debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", + pci_name(pvt->system_address), + pvt->system_address->vendor, pvt->system_address->device); + debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", + pci_name(pvt->branchmap_werrors), + pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device); + debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n", + pci_name(pvt->fsb_error_regs), + pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device); + + pvt->branch_0 = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_5400_FBD0, NULL); + if (!pvt->branch_0) { + i5400_printk(KERN_ERR, + "MC: 'BRANCH 0' device not found:" + "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0); + goto error; + } + + /* If this device claims to have more than 2 channels then + * fetch Branch 1's information + */ + if (pvt->maxch < CHANNELS_PER_BRANCH) + return 0; + + pvt->branch_1 = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_5400_FBD1, NULL); + if (!pvt->branch_1) { + i5400_printk(KERN_ERR, + "MC: 'BRANCH 1' device not found:" + "vendor 0x%x device 0x%x Func 0 " + "(broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_5400_FBD1); + goto error; + } + + return 0; + +error: + i5400_put_devices(mci); + return -ENODEV; +} + +/* + * determine_amb_present + * + * the information is contained in NUM_MTRS_PER_BRANCH different + * registers determining which of the NUM_MTRS_PER_BRANCH requires + * knowing which channel is in question + * + * 2 branches, each with 2 channels + * b0_ambpresent0 for channel '0' + * b0_ambpresent1 for channel '1' + * b1_ambpresent0 for channel '2' + * b1_ambpresent1 for channel '3' + */ +static int determine_amb_present_reg(struct i5400_pvt *pvt, int channel) +{ + int amb_present; + + if (channel < CHANNELS_PER_BRANCH) { + if (channel & 0x1) + amb_present = pvt->b0_ambpresent1; + else + amb_present = pvt->b0_ambpresent0; + } else { + if (channel & 0x1) + amb_present = pvt->b1_ambpresent1; + else + amb_present = pvt->b1_ambpresent0; + } + + return amb_present; +} + +/* + * determine_mtr(pvt, csrow, channel) + * + * return the proper MTR register as determine by the csrow and desired channel + */ +static int determine_mtr(struct i5400_pvt *pvt, int csrow, int channel) +{ + int mtr; + int n; + + /* There is one MTR for each slot pair of FB-DIMMs, + Each slot may have one or two ranks (2 csrows), + Each slot pair may be at branch 0 or branch 1. + So, csrow should be divided by eight + */ + n = csrow >> 3; + + if (n >= NUM_MTRS_PER_BRANCH) { + debugf0("ERROR: trying to access an invalid csrow: %d\n", + csrow); + return 0; + } + + if (channel < CHANNELS_PER_BRANCH) + mtr = pvt->b0_mtr[n]; + else + mtr = pvt->b1_mtr[n]; + + return mtr; +} + +/* + */ +static void decode_mtr(int slot_row, u16 mtr) +{ + int ans; + + ans = MTR_DIMMS_PRESENT(mtr); + + debugf2("\tMTR%d=0x%x: DIMMs are %s\n", slot_row, mtr, + ans ? "Present" : "NOT Present"); + if (!ans) + return; + + debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); + + debugf2("\t\tELECTRICAL THROTTLING is %s\n", + MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled"); + + debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); + debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single"); + debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]); + debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); +} + +static void handle_channel(struct i5400_pvt *pvt, int csrow, int channel, + struct i5400_dimm_info *dinfo) +{ + int mtr; + int amb_present_reg; + int addrBits; + + mtr = determine_mtr(pvt, csrow, channel); + if (MTR_DIMMS_PRESENT(mtr)) { + amb_present_reg = determine_amb_present_reg(pvt, channel); + + /* Determine if there is a DIMM present in this DIMM slot */ + if (amb_present_reg & (1 << (csrow >> 1))) { + dinfo->dual_rank = MTR_DIMM_RANK(mtr); + + if (!((dinfo->dual_rank == 0) && + ((csrow & 0x1) == 0x1))) { + /* Start with the number of bits for a Bank + * on the DRAM */ + addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); + /* Add thenumber of ROW bits */ + addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); + /* add the number of COLUMN bits */ + addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); + + addrBits += 6; /* add 64 bits per DIMM */ + addrBits -= 20; /* divide by 2^^20 */ + addrBits -= 3; /* 8 bits per bytes */ + + dinfo->megabytes = 1 << addrBits; + } + } + } +} + +/* + * calculate_dimm_size + * + * also will output a DIMM matrix map, if debug is enabled, for viewing + * how the DIMMs are populated + */ +static void calculate_dimm_size(struct i5400_pvt *pvt) +{ + struct i5400_dimm_info *dinfo; + int csrow, max_csrows; + char *p, *mem_buffer; + int space, n; + int channel; + + /* ================= Generate some debug output ================= */ + space = PAGE_SIZE; + mem_buffer = p = kmalloc(space, GFP_KERNEL); + if (p == NULL) { + i5400_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n", + __FILE__, __func__); + return; + } + + /* Scan all the actual CSROWS (which is # of DIMMS * 2) + * and calculate the information for each DIMM + * Start with the highest csrow first, to display it first + * and work toward the 0th csrow + */ + max_csrows = pvt->maxdimmperch * 2; + for (csrow = max_csrows - 1; csrow >= 0; csrow--) { + + /* on an odd csrow, first output a 'boundary' marker, + * then reset the message buffer */ + if (csrow & 0x1) { + n = snprintf(p, space, "---------------------------" + "--------------------------------"); + p += n; + space -= n; + debugf2("%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + } + n = snprintf(p, space, "csrow %2d ", csrow); + p += n; + space -= n; + + for (channel = 0; channel < pvt->maxch; channel++) { + dinfo = &pvt->dimm_info[csrow][channel]; + handle_channel(pvt, csrow, channel, dinfo); + n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); + p += n; + space -= n; + } + debugf2("%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + } + + /* Output the last bottom 'boundary' marker */ + n = snprintf(p, space, "---------------------------" + "--------------------------------"); + p += n; + space -= n; + debugf2("%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + /* now output the 'channel' labels */ + n = snprintf(p, space, " "); + p += n; + space -= n; + for (channel = 0; channel < pvt->maxch; channel++) { + n = snprintf(p, space, "channel %d | ", channel); + p += n; + space -= n; + } + + /* output the last message and free buffer */ + debugf2("%s\n", mem_buffer); + kfree(mem_buffer); +} + +/* + * i5400_get_mc_regs read in the necessary registers and + * cache locally + * + * Fills in the private data members + */ +static void i5400_get_mc_regs(struct mem_ctl_info *mci) +{ + struct i5400_pvt *pvt; + u32 actual_tolm; + u16 limit; + int slot_row; + int maxch; + int maxdimmperch; + int way0, way1; + + pvt = mci->pvt_info; + + pci_read_config_dword(pvt->system_address, AMBASE, + (u32 *) &pvt->ambase); + pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32), + ((u32 *) &pvt->ambase) + sizeof(u32)); + + maxdimmperch = pvt->maxdimmperch; + maxch = pvt->maxch; + + debugf2("AMBASE= 0x%lx MAXCH= %d MAX-DIMM-Per-CH= %d\n", + (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch); + + /* Get the Branch Map regs */ + pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm); + pvt->tolm >>= 12; + debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm, + pvt->tolm); + + actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28)); + debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n", + actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28); + + pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0); + pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1); + + /* Get the MIR[0-1] regs */ + limit = (pvt->mir0 >> 4) & 0x0fff; + way0 = pvt->mir0 & 0x1; + way1 = pvt->mir0 & 0x2; + debugf2("MIR0: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); + limit = (pvt->mir1 >> 4) & 0xfff; + way0 = pvt->mir1 & 0x1; + way1 = pvt->mir1 & 0x2; + debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); + + /* Get the set of MTR[0-3] regs by each branch */ + for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) { + int where = MTR0 + (slot_row * sizeof(u32)); + + /* Branch 0 set of MTR registers */ + pci_read_config_word(pvt->branch_0, where, + &pvt->b0_mtr[slot_row]); + + debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where, + pvt->b0_mtr[slot_row]); + + if (pvt->maxch < CHANNELS_PER_BRANCH) { + pvt->b1_mtr[slot_row] = 0; + continue; + } + + /* Branch 1 set of MTR registers */ + pci_read_config_word(pvt->branch_1, where, + &pvt->b1_mtr[slot_row]); + debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row, where, + pvt->b1_mtr[slot_row]); + } + + /* Read and dump branch 0's MTRs */ + debugf2("\nMemory Technology Registers:\n"); + debugf2(" Branch 0:\n"); + for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) + decode_mtr(slot_row, pvt->b0_mtr[slot_row]); + + pci_read_config_word(pvt->branch_0, AMBPRESENT_0, + &pvt->b0_ambpresent0); + debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0); + pci_read_config_word(pvt->branch_0, AMBPRESENT_1, + &pvt->b0_ambpresent1); + debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1); + + /* Only if we have 2 branchs (4 channels) */ + if (pvt->maxch < CHANNELS_PER_BRANCH) { + pvt->b1_ambpresent0 = 0; + pvt->b1_ambpresent1 = 0; + } else { + /* Read and dump branch 1's MTRs */ + debugf2(" Branch 1:\n"); + for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) + decode_mtr(slot_row, pvt->b1_mtr[slot_row]); + + pci_read_config_word(pvt->branch_1, AMBPRESENT_0, + &pvt->b1_ambpresent0); + debugf2("\t\tAMB-Branch 1-present0 0x%x:\n", + pvt->b1_ambpresent0); + pci_read_config_word(pvt->branch_1, AMBPRESENT_1, + &pvt->b1_ambpresent1); + debugf2("\t\tAMB-Branch 1-present1 0x%x:\n", + pvt->b1_ambpresent1); + } + + /* Go and determine the size of each DIMM and place in an + * orderly matrix */ + calculate_dimm_size(pvt); +} + +/* + * i5400_init_csrows Initialize the 'csrows' table within + * the mci control structure with the + * addressing of memory. + * + * return: + * 0 success + * 1 no actual memory found on this MC + */ +static int i5400_init_csrows(struct mem_ctl_info *mci) +{ + struct i5400_pvt *pvt; + struct csrow_info *p_csrow; + int empty, channel_count; + int max_csrows; + int mtr; + int csrow_megs; + int channel; + int csrow; + + pvt = mci->pvt_info; + + channel_count = pvt->maxch; + max_csrows = pvt->maxdimmperch * 2; + + empty = 1; /* Assume NO memory */ + + for (csrow = 0; csrow < max_csrows; csrow++) { + p_csrow = &mci->csrows[csrow]; + + p_csrow->csrow_idx = csrow; + + /* use branch 0 for the basis */ + mtr = determine_mtr(pvt, csrow, 0); + + /* if no DIMMS on this row, continue */ + if (!MTR_DIMMS_PRESENT(mtr)) + continue; + + /* FAKE OUT VALUES, FIXME */ + p_csrow->first_page = 0 + csrow * 20; + p_csrow->last_page = 9 + csrow * 20; + p_csrow->page_mask = 0xFFF; + + p_csrow->grain = 8; + + csrow_megs = 0; + for (channel = 0; channel < pvt->maxch; channel++) + csrow_megs += pvt->dimm_info[csrow][channel].megabytes; + + p_csrow->nr_pages = csrow_megs << 8; + + /* Assume DDR2 for now */ + p_csrow->mtype = MEM_FB_DDR2; + + /* ask what device type on this row */ + if (MTR_DRAM_WIDTH(mtr)) + p_csrow->dtype = DEV_X8; + else + p_csrow->dtype = DEV_X4; + + p_csrow->edac_mode = EDAC_S8ECD8ED; + + empty = 0; + } + + return empty; +} + +/* + * i5400_enable_error_reporting + * Turn on the memory reporting features of the hardware + */ +static void i5400_enable_error_reporting(struct mem_ctl_info *mci) +{ + struct i5400_pvt *pvt; + u32 fbd_error_mask; + + pvt = mci->pvt_info; + + /* Read the FBD Error Mask Register */ + pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD, + &fbd_error_mask); + + /* Enable with a '0' */ + fbd_error_mask &= ~(ENABLE_EMASK_ALL); + + pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD, + fbd_error_mask); +} + +/* + * i5400_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels) + * + * ask the device how many channels are present and how many CSROWS + * as well + */ +static void i5400_get_dimm_and_channel_counts(struct pci_dev *pdev, + int *num_dimms_per_channel, + int *num_channels) +{ + u8 value; + + /* Need to retrieve just how many channels and dimms per channel are + * supported on this memory controller + */ + pci_read_config_byte(pdev, MAXDIMMPERCH, &value); + *num_dimms_per_channel = (int)value * 2; + + pci_read_config_byte(pdev, MAXCH, &value); + *num_channels = (int)value; +} + +/* + * i5400_probe1 Probe for ONE instance of device to see if it is + * present. + * return: + * 0 for FOUND a device + * < 0 for error code + */ +static int i5400_probe1(struct pci_dev *pdev, int dev_idx) +{ + struct mem_ctl_info *mci; + struct i5400_pvt *pvt; + int num_channels; + int num_dimms_per_channel; + int num_csrows; + + if (dev_idx >= ARRAY_SIZE(i5400_devs)) + return -EINVAL; + + debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", + __func__, + pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + + /* We only are looking for func 0 of the set */ + if (PCI_FUNC(pdev->devfn) != 0) + return -ENODEV; + + /* Ask the devices for the number of CSROWS and CHANNELS so + * that we can calculate the memory resources, etc + * + * The Chipset will report what it can handle which will be greater + * or equal to what the motherboard manufacturer will implement. + * + * As we don't have a motherboard identification routine to determine + * actual number of slots/dimms per channel, we thus utilize the + * resource as specified by the chipset. Thus, we might have + * have more DIMMs per channel than actually on the mobo, but this + * allows the driver to support upto the chipset max, without + * some fancy mobo determination. + */ + i5400_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel, + &num_channels); + num_csrows = num_dimms_per_channel * 2; + + debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", + __func__, num_channels, num_dimms_per_channel, num_csrows); + + /* allocate a new MC control structure */ + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + + if (mci == NULL) + return -ENOMEM; + + debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + + mci->dev = &pdev->dev; /* record ptr to the generic device */ + + pvt = mci->pvt_info; + pvt->system_address = pdev; /* Record this device in our private */ + pvt->maxch = num_channels; + pvt->maxdimmperch = num_dimms_per_channel; + + /* 'get' the pci devices we want to reserve for our use */ + if (i5400_get_devices(mci, dev_idx)) + goto fail0; + + /* Time to get serious */ + i5400_get_mc_regs(mci); /* retrieve the hardware registers */ + + mci->mc_idx = 0; + mci->mtype_cap = MEM_FLAG_FB_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE; + mci->edac_cap = EDAC_FLAG_NONE; + mci->mod_name = "i5400_edac.c"; + mci->mod_ver = I5400_REVISION; + mci->ctl_name = i5400_devs[dev_idx].ctl_name; + mci->dev_name = pci_name(pdev); + mci->ctl_page_to_phys = NULL; + + /* Set the function pointer to an actual operation function */ + mci->edac_check = i5400_check_error; + + /* initialize the MC control structure 'csrows' table + * with the mapping and control information */ + if (i5400_init_csrows(mci)) { + debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" + " because i5400_init_csrows() returned nonzero " + "value\n"); + mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ + } else { + debugf1("MC: Enable error reporting now\n"); + i5400_enable_error_reporting(mci); + } + + /* add this new MC control structure to EDAC's list of MCs */ + if (edac_mc_add_mc(mci)) { + debugf0("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", __func__); + /* FIXME: perhaps some code should go here that disables error + * reporting if we just enabled it + */ + goto fail1; + } + + i5400_clear_error(mci); + + /* allocating generic PCI control info */ + i5400_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + if (!i5400_pci) { + printk(KERN_WARNING + "%s(): Unable to create PCI control\n", + __func__); + printk(KERN_WARNING + "%s(): PCI error report via EDAC not setup\n", + __func__); + } + + return 0; + + /* Error exit unwinding stack */ +fail1: + + i5400_put_devices(mci); + +fail0: + edac_mc_free(mci); + return -ENODEV; +} + +/* + * i5400_init_one constructor for one instance of device + * + * returns: + * negative on error + * count (>= 0) + */ +static int __devinit i5400_init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int rc; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* wake up device */ + rc = pci_enable_device(pdev); + if (rc == -EIO) + return rc; + + /* now probe and enable the device */ + return i5400_probe1(pdev, id->driver_data); +} + +/* + * i5400_remove_one destructor for one instance of device + * + */ +static void __devexit i5400_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + + debugf0(__FILE__ ": %s()\n", __func__); + + if (i5400_pci) + edac_pci_release_generic_ctl(i5400_pci); + + mci = edac_mc_del_mc(&pdev->dev); + if (!mci) + return; + + /* retrieve references to resources, and free those resources */ + i5400_put_devices(mci); + + edac_mc_free(mci); +} + +/* + * pci_device_id table for which devices we are looking for + * + * The "E500P" device is the first device supported. + */ +static const struct pci_device_id i5400_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR)}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, i5400_pci_tbl); + +/* + * i5400_driver pci_driver structure for this module + * + */ +static struct pci_driver i5400_driver = { + .name = "i5400_edac", + .probe = i5400_init_one, + .remove = __devexit_p(i5400_remove_one), + .id_table = i5400_pci_tbl, +}; + +/* + * i5400_init Module entry function + * Try to initialize this module for its devices + */ +static int __init i5400_init(void) +{ + int pci_rc; + + debugf2("MC: " __FILE__ ": %s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + + pci_rc = pci_register_driver(&i5400_driver); + + return (pci_rc < 0) ? pci_rc : 0; +} + +/* + * i5400_exit() Module exit function + * Unregister the driver + */ +static void __exit i5400_exit(void) +{ + debugf2("MC: " __FILE__ ": %s()\n", __func__); + pci_unregister_driver(&i5400_driver); +} + +module_init(i5400_init); +module_exit(i5400_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ben Woodard <woodard@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("MC Driver for Intel I5400 memory controllers - " + I5400_REVISION); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index ebb037b78758..b2d83b95033d 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -311,9 +311,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, } /* cache is irrelevant for PCI bus reads/writes */ - window = ioremap_nocache(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); - + window = pci_ioremap_bar(dev, 0); if (window == NULL) { i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n", __func__); diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 0cfcb2d075a0..853ef37ec006 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -630,27 +630,22 @@ static int mpc85xx_l2_err_remove(struct of_device *op) } static struct of_device_id mpc85xx_l2_err_of_match[] = { - { - .compatible = "fsl,8540-l2-cache-controller", - }, - { - .compatible = "fsl,8541-l2-cache-controller", - }, - { - .compatible = "fsl,8544-l2-cache-controller", - }, - { - .compatible = "fsl,8548-l2-cache-controller", - }, - { - .compatible = "fsl,8555-l2-cache-controller", - }, - { - .compatible = "fsl,8568-l2-cache-controller", - }, - { - .compatible = "fsl,mpc8572-l2-cache-controller", - }, +/* deprecate the fsl,85.. forms in the future, 2.6.30? */ + { .compatible = "fsl,8540-l2-cache-controller", }, + { .compatible = "fsl,8541-l2-cache-controller", }, + { .compatible = "fsl,8544-l2-cache-controller", }, + { .compatible = "fsl,8548-l2-cache-controller", }, + { .compatible = "fsl,8555-l2-cache-controller", }, + { .compatible = "fsl,8568-l2-cache-controller", }, + { .compatible = "fsl,mpc8536-l2-cache-controller", }, + { .compatible = "fsl,mpc8540-l2-cache-controller", }, + { .compatible = "fsl,mpc8541-l2-cache-controller", }, + { .compatible = "fsl,mpc8544-l2-cache-controller", }, + { .compatible = "fsl,mpc8548-l2-cache-controller", }, + { .compatible = "fsl,mpc8555-l2-cache-controller", }, + { .compatible = "fsl,mpc8560-l2-cache-controller", }, + { .compatible = "fsl,mpc8568-l2-cache-controller", }, + { .compatible = "fsl,mpc8572-l2-cache-controller", }, {}, }; @@ -967,27 +962,22 @@ static int mpc85xx_mc_err_remove(struct of_device *op) } static struct of_device_id mpc85xx_mc_err_of_match[] = { - { - .compatible = "fsl,8540-memory-controller", - }, - { - .compatible = "fsl,8541-memory-controller", - }, - { - .compatible = "fsl,8544-memory-controller", - }, - { - .compatible = "fsl,8548-memory-controller", - }, - { - .compatible = "fsl,8555-memory-controller", - }, - { - .compatible = "fsl,8568-memory-controller", - }, - { - .compatible = "fsl,mpc8572-memory-controller", - }, +/* deprecate the fsl,85.. forms in the future, 2.6.30? */ + { .compatible = "fsl,8540-memory-controller", }, + { .compatible = "fsl,8541-memory-controller", }, + { .compatible = "fsl,8544-memory-controller", }, + { .compatible = "fsl,8548-memory-controller", }, + { .compatible = "fsl,8555-memory-controller", }, + { .compatible = "fsl,8568-memory-controller", }, + { .compatible = "fsl,mpc8536-memory-controller", }, + { .compatible = "fsl,mpc8540-memory-controller", }, + { .compatible = "fsl,mpc8541-memory-controller", }, + { .compatible = "fsl,mpc8544-memory-controller", }, + { .compatible = "fsl,mpc8548-memory-controller", }, + { .compatible = "fsl,mpc8555-memory-controller", }, + { .compatible = "fsl,mpc8560-memory-controller", }, + { .compatible = "fsl,mpc8568-memory-controller", }, + { .compatible = "fsl,mpc8572-memory-controller", }, {}, }; diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 78b989d202a3..d76adfea5df7 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -468,8 +468,8 @@ const char *dmi_get_system_info(int field) EXPORT_SYMBOL(dmi_get_system_info); /** - * dmi_name_in_serial - Check if string is in the DMI product serial - * information. + * dmi_name_in_serial - Check if string is in the DMI product serial information + * @str: string to check for */ int dmi_name_in_serial(const char *str) { @@ -585,6 +585,8 @@ EXPORT_SYMBOL_GPL(dmi_walk); /** * dmi_match - compare a string to the dmi field (if exists) + * @f: DMI field identifier + * @str: string to compare the DMI field to * * Returns true if the requested field equals to the str (including NULL). */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 48f49d93d249..3d2565441b36 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -95,7 +95,7 @@ config GPIO_MAX732X number for these GPIOs. config GPIO_PCA953X - tristate "PCA953x, PCA955x, and MAX7310 I/O ports" + tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports" depends on I2C help Say yes here to provide access to several register-oriented @@ -104,9 +104,10 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 - 8 bits: max7310, pca9534, pca9538, pca9554, pca9557 + 8 bits: max7310, pca9534, pca9538, pca9554, pca9557, + tca6408 - 16 bits: pca9535, pca9539, pca9555 + 16 bits: pca9535, pca9539, pca9555, tca6416 This driver can also be built as a module. If so, the module will be called pca953x. diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 9ceeb89f1325..37f35388a2ae 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -33,7 +33,12 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9554", 8, }, { "pca9555", 16, }, { "pca9557", 8, }, + { "max7310", 8, }, + { "pca6107", 8, }, + { "tca6408", 8, }, + { "tca6416", 16, }, + /* NYET: { "tca6424", 24, }, */ { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); @@ -47,9 +52,6 @@ struct pca953x_chip { struct gpio_chip gpio_chip; }; -/* NOTE: we can't currently rely on fault codes to come from SMBus - * calls, so we map all errors to EIO here and return zero otherwise. - */ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) { int ret; @@ -61,7 +63,7 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) if (ret < 0) { dev_err(&chip->client->dev, "failed writing register\n"); - return -EIO; + return ret; } return 0; @@ -78,7 +80,7 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); - return -EIO; + return ret; } *val = (uint16_t)ret; diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c index 37d3eec8730a..afad14792141 100644 --- a/drivers/gpio/twl4030-gpio.c +++ b/drivers/gpio/twl4030-gpio.c @@ -202,37 +202,6 @@ static int twl4030_get_gpio_datain(int gpio) return ret; } -/* - * Configure debounce timing value for a GPIO pin on TWL4030 - */ -int twl4030_set_gpio_debounce(int gpio, int enable) -{ - u8 d_bnk = gpio >> 3; - u8 d_msk = BIT(gpio & 0x7); - u8 reg = 0; - u8 base = 0; - int ret = 0; - - if (unlikely((gpio >= TWL4030_GPIO_MAX) - || !(gpio_usage_count & BIT(gpio)))) - return -EPERM; - - base = REG_GPIO_DEBEN1 + d_bnk; - mutex_lock(&gpio_lock); - ret = gpio_twl4030_read(base); - if (ret >= 0) { - if (enable) - reg = ret | d_msk; - else - reg = ret & ~d_msk; - - ret = gpio_twl4030_write(base, reg); - } - mutex_unlock(&gpio_lock); - return ret; -} -EXPORT_SYMBOL(twl4030_set_gpio_debounce); - /*----------------------------------------------------------------------*/ static int twl_request(struct gpio_chip *chip, unsigned offset) @@ -405,6 +374,23 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) REG_GPIOPUPDCTR1, 5); } +static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) +{ + u8 message[4]; + + /* 30 msec of debouncing is always used for MMC card detect, + * and is optional for everything else. + */ + message[1] = (debounce & 0xff) | (mmc_cd & 0x03); + debounce >>= 8; + message[2] = (debounce & 0xff); + debounce >>= 8; + message[3] = (debounce & 0x03); + + return twl4030_i2c_write(TWL4030_MODULE_GPIO, message, + REG_GPIO_DEBEN1, 3); +} + static int gpio_twl4030_remove(struct platform_device *pdev); static int __devinit gpio_twl4030_probe(struct platform_device *pdev) @@ -439,6 +425,12 @@ no_irqs: pdata->pullups, pdata->pulldowns, ret); + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, + ret); + twl_gpiochip.base = pdata->gpio_base; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 3733e36d135e..b06a53715853 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -183,6 +183,10 @@ int drm_stub_open(struct inode *inode, struct file *filp) old_fops = filp->f_op; filp->f_op = fops_get(&dev->driver->fops); + if (filp->f_op == NULL) { + filp->f_op = old_fops; + goto out; + } if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { fops_put(filp->f_op); filp->f_op = fops_get(old_fops); diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 66107b4dc12a..1852f27bac51 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -204,8 +204,6 @@ I2C_CLIENT_INSMOD_1(adt7462); #define MASK_AND_SHIFT(value, prefix) \ (((value) & prefix##_MASK) >> prefix##_SHIFT) -#define ROUND_DIV(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) - struct adt7462_data { struct device *hwmon_dev; struct attribute_group attrs; @@ -840,7 +838,7 @@ static ssize_t set_temp_min(struct device *dev, if (strict_strtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) return -EINVAL; - temp = ROUND_DIV(temp, 1000) + 64; + temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -878,7 +876,7 @@ static ssize_t set_temp_max(struct device *dev, if (strict_strtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) return -EINVAL; - temp = ROUND_DIV(temp, 1000) + 64; + temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -943,7 +941,7 @@ static ssize_t set_volt_max(struct device *dev, return -EINVAL; temp *= 1000; /* convert mV to uV */ - temp = ROUND_DIV(temp, x); + temp = DIV_ROUND_CLOSEST(temp, x); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -985,7 +983,7 @@ static ssize_t set_volt_min(struct device *dev, return -EINVAL; temp *= 1000; /* convert mV to uV */ - temp = ROUND_DIV(temp, x); + temp = DIV_ROUND_CLOSEST(temp, x); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -1250,7 +1248,7 @@ static ssize_t set_pwm_hyst(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 15); /* package things up */ @@ -1337,7 +1335,7 @@ static ssize_t set_pwm_tmin(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000) + 64; + temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 1311a595147e..633e1a1e9d79 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -28,6 +28,7 @@ #include <linux/mutex.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/kthread.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; @@ -74,6 +75,7 @@ I2C_CLIENT_INSMOD_1(adt7470); #define ADT7470_REG_PWM12_CFG 0x68 #define ADT7470_PWM2_AUTO_MASK 0x40 #define ADT7470_PWM1_AUTO_MASK 0x80 +#define ADT7470_PWM_AUTO_MASK 0xC0 #define ADT7470_REG_PWM34_CFG 0x69 #define ADT7470_PWM3_AUTO_MASK 0x40 #define ADT7470_PWM4_AUTO_MASK 0x80 @@ -128,8 +130,11 @@ I2C_CLIENT_INSMOD_1(adt7470); /* How often do we reread sensor limit values? (In jiffies) */ #define LIMIT_REFRESH_INTERVAL (60 * HZ) -/* sleep 1s while gathering temperature data */ -#define TEMP_COLLECTION_TIME 1000 +/* Wait at least 200ms per sensor for 10 sensors */ +#define TEMP_COLLECTION_TIME 2000 + +/* auto update thing won't fire more than every 2s */ +#define AUTO_UPDATE_INTERVAL 2000 /* datasheet says to divide this number by the fan reading to get fan rpm */ #define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) @@ -137,8 +142,6 @@ I2C_CLIENT_INSMOD_1(adt7470); #define FAN_PERIOD_INVALID 65535 #define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) -#define ROUND_DIV(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) - struct adt7470_data { struct device *hwmon_dev; struct attribute_group attrs; @@ -148,6 +151,9 @@ struct adt7470_data { unsigned long sensors_last_updated; /* In jiffies */ unsigned long limits_last_updated; /* In jiffies */ + int num_temp_sensors; /* -1 = probe */ + int temperatures_probed; + s8 temp[ADT7470_TEMP_COUNT]; s8 temp_min[ADT7470_TEMP_COUNT]; s8 temp_max[ADT7470_TEMP_COUNT]; @@ -163,6 +169,10 @@ struct adt7470_data { u8 pwm_min[ADT7470_PWM_COUNT]; s8 pwm_tmin[ADT7470_PWM_COUNT]; u8 pwm_auto_temp[ADT7470_PWM_COUNT]; + + struct task_struct *auto_update; + struct completion auto_update_stop; + unsigned int auto_update_interval; }; static int adt7470_probe(struct i2c_client *client, @@ -220,40 +230,126 @@ static void adt7470_init_client(struct i2c_client *client) } } -static struct adt7470_data *adt7470_update_device(struct device *dev) +/* Probe for temperature sensors. Assumes lock is held */ +static int adt7470_read_temperatures(struct i2c_client *client, + struct adt7470_data *data) { - struct i2c_client *client = to_i2c_client(dev); - struct adt7470_data *data = i2c_get_clientdata(client); - unsigned long local_jiffies = jiffies; - u8 cfg; + unsigned long res; int i; + u8 cfg, pwm[4], pwm_cfg[2]; - mutex_lock(&data->lock); - if (time_before(local_jiffies, data->sensors_last_updated + - SENSOR_REFRESH_INTERVAL) - && data->sensors_valid) - goto no_sensor_update; + /* save pwm[1-4] config register */ + pwm_cfg[0] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(0)); + pwm_cfg[1] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(2)); + + /* set manual pwm to whatever it is set to now */ + for (i = 0; i < ADT7470_FAN_COUNT; i++) + pwm[i] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM(i)); + + /* put pwm in manual mode */ + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0), + pwm_cfg[0] & ~(ADT7470_PWM_AUTO_MASK)); + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), + pwm_cfg[1] & ~(ADT7470_PWM_AUTO_MASK)); + + /* write pwm control to whatever it was */ + for (i = 0; i < ADT7470_FAN_COUNT; i++) + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(i), pwm[i]); /* start reading temperature sensors */ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); cfg |= 0x80; i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); - /* - * Delay is 200ms * number of tmp05 sensors. Too bad - * there's no way to figure out how many are connected. - * For now, assume 1s will work. - */ - msleep(TEMP_COLLECTION_TIME); + /* Delay is 200ms * number of temp sensors. */ + res = msleep_interruptible((data->num_temp_sensors >= 0 ? + data->num_temp_sensors * 200 : + TEMP_COLLECTION_TIME)); /* done reading temperature sensors */ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); cfg &= ~0x80; i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); - for (i = 0; i < ADT7470_TEMP_COUNT; i++) + /* restore pwm[1-4] config registers */ + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]); + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]); + + if (res) { + printk(KERN_ERR "ha ha, interrupted"); + return -EAGAIN; + } + + /* Only count fans if we have to */ + if (data->num_temp_sensors >= 0) + return 0; + + for (i = 0; i < ADT7470_TEMP_COUNT; i++) { data->temp[i] = i2c_smbus_read_byte_data(client, ADT7470_TEMP_REG(i)); + if (data->temp[i]) + data->num_temp_sensors = i + 1; + } + data->temperatures_probed = 1; + return 0; +} + +static int adt7470_update_thread(void *p) +{ + struct i2c_client *client = p; + struct adt7470_data *data = i2c_get_clientdata(client); + + while (!kthread_should_stop()) { + mutex_lock(&data->lock); + adt7470_read_temperatures(client, data); + mutex_unlock(&data->lock); + if (kthread_should_stop()) + break; + msleep_interruptible(data->auto_update_interval); + } + + complete_all(&data->auto_update_stop); + return 0; +} + +static struct adt7470_data *adt7470_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + unsigned long local_jiffies = jiffies; + u8 cfg; + int i; + int need_sensors = 1; + int need_limits = 1; + + /* + * Figure out if we need to update the shadow registers. + * Lockless means that we may occasionally report out of + * date data. + */ + if (time_before(local_jiffies, data->sensors_last_updated + + SENSOR_REFRESH_INTERVAL) && + data->sensors_valid) + need_sensors = 0; + + if (time_before(local_jiffies, data->limits_last_updated + + LIMIT_REFRESH_INTERVAL) && + data->limits_valid) + need_limits = 0; + + if (!need_sensors && !need_limits) + return data; + + mutex_lock(&data->lock); + if (!need_sensors) + goto no_sensor_update; + + if (!data->temperatures_probed) + adt7470_read_temperatures(client, data); + else + for (i = 0; i < ADT7470_TEMP_COUNT; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_REG(i)); for (i = 0; i < ADT7470_FAN_COUNT; i++) data->fan[i] = adt7470_read_word_data(client, @@ -302,9 +398,7 @@ static struct adt7470_data *adt7470_update_device(struct device *dev) data->sensors_valid = 1; no_sensor_update: - if (time_before(local_jiffies, data->limits_last_updated + - LIMIT_REFRESH_INTERVAL) - && data->limits_valid) + if (!need_limits) goto out; for (i = 0; i < ADT7470_TEMP_COUNT; i++) { @@ -338,6 +432,66 @@ out: return data; } +static ssize_t show_auto_update_interval(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->auto_update_interval); +} + +static ssize_t set_auto_update_interval(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + long temp; + + if (strict_strtol(buf, 10, &temp)) + return -EINVAL; + + temp = SENSORS_LIMIT(temp, 0, 60000); + + mutex_lock(&data->lock); + data->auto_update_interval = temp; + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_num_temp_sensors(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->num_temp_sensors); +} + +static ssize_t set_num_temp_sensors(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + long temp; + + if (strict_strtol(buf, 10, &temp)) + return -EINVAL; + + temp = SENSORS_LIMIT(temp, -1, 10); + + mutex_lock(&data->lock); + data->num_temp_sensors = temp; + if (temp < 0) + data->temperatures_probed = 0; + mutex_unlock(&data->lock); + + return count; +} + static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf) @@ -360,7 +514,7 @@ static ssize_t set_temp_min(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -394,7 +548,7 @@ static ssize_t set_temp_max(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -671,7 +825,7 @@ static ssize_t set_pwm_tmin(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -804,6 +958,10 @@ static ssize_t show_alarm(struct device *dev, } static DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarm_mask, NULL); +static DEVICE_ATTR(num_temp_sensors, S_IWUSR | S_IRUGO, show_num_temp_sensors, + set_num_temp_sensors); +static DEVICE_ATTR(auto_update_interval, S_IWUSR | S_IRUGO, + show_auto_update_interval, set_auto_update_interval); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max, 0); @@ -976,6 +1134,8 @@ static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, static struct attribute *adt7470_attr[] = { &dev_attr_alarm_mask.attr, + &dev_attr_num_temp_sensors.attr, + &dev_attr_auto_update_interval.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, @@ -1108,6 +1268,9 @@ static int adt7470_probe(struct i2c_client *client, goto exit; } + data->num_temp_sensors = -1; + data->auto_update_interval = AUTO_UPDATE_INTERVAL; + i2c_set_clientdata(client, data); mutex_init(&data->lock); @@ -1127,8 +1290,16 @@ static int adt7470_probe(struct i2c_client *client, goto exit_remove; } + init_completion(&data->auto_update_stop); + data->auto_update = kthread_run(adt7470_update_thread, client, + dev_name(data->hwmon_dev)); + if (IS_ERR(data->auto_update)) + goto exit_unregister; + return 0; +exit_unregister: + hwmon_device_unregister(data->hwmon_dev); exit_remove: sysfs_remove_group(&client->dev.kobj, &data->attrs); exit_free: @@ -1141,6 +1312,8 @@ static int adt7470_remove(struct i2c_client *client) { struct adt7470_data *data = i2c_get_clientdata(client); + kthread_stop(data->auto_update); + wait_for_completion(&data->auto_update_stop); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->attrs); kfree(data); diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c index 18aa30866a6c..0a6ce2367b42 100644 --- a/drivers/hwmon/adt7473.c +++ b/drivers/hwmon/adt7473.c @@ -129,8 +129,6 @@ I2C_CLIENT_INSMOD_1(adt7473); #define FAN_PERIOD_INVALID 65535 #define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) -#define ROUND_DIV(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) - struct adt7473_data { struct device *hwmon_dev; struct attribute_group attrs; @@ -459,7 +457,7 @@ static ssize_t set_temp_min(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); @@ -495,7 +493,7 @@ static ssize_t set_temp_max(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); @@ -720,7 +718,7 @@ static ssize_t set_temp_tmax(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); @@ -756,7 +754,7 @@ static ssize_t set_temp_tmin(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 086c2a5cef0b..dca47a591baf 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -131,6 +131,10 @@ static const char* temperature_sensors_sets[][36] = { /* Set 14: iMac 6,1 */ { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P", "TO0P", "Tp0P", NULL }, +/* Set 15: MacBook Air 2,1 */ + { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0", + "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P", + "Ts0S", NULL }, }; /* List of keys used to read/write fan speeds */ @@ -1301,11 +1305,17 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = { { .accelerometer = 0, .light = 0, .temperature_set = 13 }, /* iMac 6: light sensor only, temperature set 14 */ { .accelerometer = 0, .light = 0, .temperature_set = 14 }, +/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */ + { .accelerometer = 1, .light = 1, .temperature_set = 15 }, }; /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ static __initdata struct dmi_system_id applesmc_whitelist[] = { + { applesmc_dmi_match, "Apple MacBook Air 2", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") }, + &applesmc_dmi_data[15]}, { applesmc_dmi_match, "Apple MacBook Air", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") }, diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 537d9fb2ff88..a36363312f2f 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -40,7 +40,7 @@ static inline u16 extract_value(const char *data, int offset) { - return be16_to_cpup((u16 *)&data[offset]); + return be16_to_cpup((__be16 *)&data[offset]); } #define TEMP_SENSOR 1 diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 4ee85fcf9aaf..3f9503867e6b 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -511,6 +511,13 @@ config BLK_DEV_PIIX This allows the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. +config BLK_DEV_IT8172 + tristate "IT8172 IDE support" + select BLK_DEV_IDEDMA_PCI + help + This driver adds support for the IDE controller on the + IT8172 System Controller. + config BLK_DEV_IT8213 tristate "IT8213 IDE support" select BLK_DEV_IDEDMA_PCI diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 410728992e6a..c2b9c93f0095 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o +obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c index 4142c698e0d3..4485b9c6f0e6 100644 --- a/drivers/ide/aec62xx.c +++ b/drivers/ide/aec62xx.c @@ -83,7 +83,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr static void aec6210_set_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_host *host = pci_get_drvdata(dev); struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; @@ -111,7 +111,7 @@ static void aec6210_set_mode(ide_drive_t *drive, const u8 speed) static void aec6260_set_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_host *host = pci_get_drvdata(dev); struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c index 45d2356bb725..66f43083408b 100644 --- a/drivers/ide/alim15x3.c +++ b/drivers/ide/alim15x3.c @@ -68,7 +68,7 @@ static struct pci_dev *isa_dev; static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); int s_time = t->setup, a_time = t->active, c_time = t->cycle; @@ -150,7 +150,7 @@ static u8 ali_udma_filter(ide_drive_t *drive) static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 speed1 = speed; u8 unit = drive->dn & 1; @@ -198,7 +198,7 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) static int ali15x3_dma_setup(ide_drive_t *drive) { if (m5229_revision < 0xC2 && drive->media != ide_disk) { - if (rq_data_dir(drive->hwif->hwgroup->rq)) + if (rq_data_dir(drive->hwif->rq)) return 1; /* try PIO instead of DMA */ } return ide_dma_setup(drive); @@ -490,8 +490,6 @@ static int __devinit init_dma_ali15x3(ide_hwif_t *hwif, if (ide_allocate_dma_engine(hwif)) return -1; - hwif->dma_ops = &sff_dma_ops; - return 0; } @@ -511,6 +509,7 @@ static const struct ide_dma_ops ali_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_port_info ali15x3_chipset __devinitdata = { @@ -519,6 +518,7 @@ static const struct ide_port_info ali15x3_chipset __devinitdata = { .init_hwif = init_hwif_ali15x3, .init_dma = init_dma_ali15x3, .port_ops = &ali_port_ops, + .dma_ops = &sff_dma_ops, .pio_mask = ATA_PIO5, .swdma_mask = ATA_SWDMA2, .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c index c6bcd3014a29..69660a431cd9 100644 --- a/drivers/ide/amd74xx.c +++ b/drivers/ide/amd74xx.c @@ -82,7 +82,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); - ide_drive_t *peer = hwif->drives + (~drive->dn & 1); + ide_drive_t *peer = ide_get_pair_dev(drive); struct ide_timing t, p; int T, UT; u8 udma_mask = hwif->ultra_mask; @@ -92,7 +92,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed) ide_timing_compute(drive, speed, &t, T, UT); - if (peer->dev_flags & IDE_DFLAG_PRESENT) { + if (peer) { ide_timing_compute(peer, peer->current_speed, &p, T, UT); ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); } diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c index 0ec8fd1e4dcb..79a2dfed8eb7 100644 --- a/drivers/ide/au1xxx-ide.c +++ b/drivers/ide/au1xxx-ide.c @@ -212,8 +212,8 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed) static int auide_build_dmatable(ide_drive_t *drive) { int i, iswrite, count = 0; - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = HWGROUP(drive)->rq; + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; _auide_hwif *ahwif = &auide_hwif; struct scatterlist *sg; @@ -286,7 +286,7 @@ static int auide_build_dmatable(ide_drive_t *drive) static int auide_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; if (hwif->sg_nents) { ide_destroy_dmatable(drive); @@ -309,8 +309,8 @@ static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command) } static int auide_dma_setup(ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; +{ + struct request *rq = drive->hwif->rq; if (!auide_build_dmatable(drive)) { ide_map_sg(drive, rq); @@ -502,7 +502,6 @@ static const struct ide_tp_ops au1xxx_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index e4306647d00d..8890276fef7f 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -467,11 +467,10 @@ static void program_drive_counts(ide_drive_t *drive, unsigned int index) * so we merge the timings, using the slowest value for each timing. */ if (index > 1) { - ide_hwif_t *hwif = drive->hwif; - ide_drive_t *peer = &hwif->drives[!(drive->dn & 1)]; + ide_drive_t *peer = ide_get_pair_dev(drive); unsigned int mate = index ^ 1; - if (peer->dev_flags & IDE_DFLAG_PRESENT) { + if (peer) { if (setup_count < setup_counts[mate]) setup_count = setup_counts[mate]; if (active_count < active_counts[mate]) diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 3623bf013bcf..2f9688d87ecd 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -115,7 +115,7 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_ */ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); unsigned int cycle_time; @@ -138,10 +138,12 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) * the slowest address setup timing ourselves. */ if (hwif->channel) { - ide_drive_t *drives = hwif->drives; + ide_drive_t *pair = ide_get_pair_dev(drive); drive->drive_data = setup_count; - setup_count = max(drives[0].drive_data, drives[1].drive_data); + + if (pair) + setup_count = max_t(u8, setup_count, pair->drive_data); } if (setup_count > 5) /* shouldn't actually happen... */ @@ -180,7 +182,7 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 unit = drive->dn & 0x01; u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; @@ -226,7 +228,7 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) static int cmd648_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long base = hwif->dma_base - (hwif->channel * 8); int err = ide_dma_end(drive); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : @@ -242,7 +244,7 @@ static int cmd648_dma_end(ide_drive_t *drive) static int cmd64x_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int irq_reg = hwif->channel ? ARTTIM23 : CFR; u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : @@ -259,7 +261,7 @@ static int cmd64x_dma_end(ide_drive_t *drive) static int cmd648_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long base = hwif->dma_base - (hwif->channel * 8); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; @@ -282,7 +284,7 @@ static int cmd648_dma_test_irq(ide_drive_t *drive) static int cmd64x_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int irq_reg = hwif->channel ? ARTTIM23 : CFR; u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : @@ -313,7 +315,7 @@ static int cmd64x_dma_test_irq(ide_drive_t *drive) static int cmd646_1_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u8 dma_stat = 0, dma_cmd = 0; drive->waiting_for_dma = 0; @@ -383,6 +385,7 @@ static const struct ide_dma_ops cmd64x_dma_ops = { .dma_test_irq = cmd64x_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_dma_ops cmd646_rev1_dma_ops = { @@ -394,6 +397,7 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_dma_ops cmd648_dma_ops = { @@ -405,6 +409,7 @@ static const struct ide_dma_ops cmd648_dma_ops = { .dma_test_irq = cmd648_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c index 5efb467f8fa0..d003bec56ff9 100644 --- a/drivers/ide/cs5520.c +++ b/drivers/ide/cs5520.c @@ -59,7 +59,7 @@ static struct pio_clocks cs5520_pio_clocks[]={ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *pdev = to_pci_dev(hwif->dev); int controller = drive->dn > 1 ? 1 : 0; diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c index d37baf8ecc5f..74fc5401f407 100644 --- a/drivers/ide/cy82c693.c +++ b/drivers/ide/cy82c693.c @@ -203,7 +203,7 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode) static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); pio_clocks_t pclk; unsigned int addrCtrl; diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c index 39d500d84b07..a5ba820d69bb 100644 --- a/drivers/ide/falconide.c +++ b/drivers/ide/falconide.c @@ -70,7 +70,6 @@ static const struct ide_tp_ops falconide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index b18e10d99d2e..3eb9b5c63a0f 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -626,7 +626,7 @@ static struct hpt_info *hpt3xx_get_info(struct device *dev) static u8 hpt3xx_udma_filter(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct hpt_info *info = hpt3xx_get_info(hwif->dev); u8 mask = hwif->ultra_mask; @@ -665,7 +665,7 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive) static u8 hpt3xx_mdma_filter(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct hpt_info *info = hpt3xx_get_info(hwif->dev); switch (info->chip_type) { @@ -743,7 +743,7 @@ static void hpt3xx_quirkproc(ide_drive_t *drive) static void hpt3xx_maskproc(ide_drive_t *drive, int mask) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct hpt_info *info = hpt3xx_get_info(hwif->dev); @@ -788,7 +788,7 @@ static void hpt366_dma_lost_irq(ide_drive_t *drive) static void hpt370_clear_engine(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); pci_write_config_byte(dev, hwif->select_data, 0x37); @@ -797,7 +797,7 @@ static void hpt370_clear_engine(ide_drive_t *drive) static void hpt370_irq_timeout(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u16 bfifo = 0; u8 dma_cmd; @@ -822,7 +822,7 @@ static void hpt370_dma_start(ide_drive_t *drive) static int hpt370_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); if (dma_stat & 0x01) { @@ -844,7 +844,7 @@ static void hpt370_dma_timeout(ide_drive_t *drive) /* returns 1 if DMA IRQ issued, 0 otherwise */ static int hpt374_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u16 bfifo = 0; u8 dma_stat; @@ -865,7 +865,7 @@ static int hpt374_dma_test_irq(ide_drive_t *drive) static int hpt374_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 mcr = 0, mcr_addr = hwif->select_data; u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; @@ -927,7 +927,7 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) { - hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21); + hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x23 : 0x21); } /** @@ -1349,8 +1349,6 @@ static int __devinit init_dma_hpt366(ide_hwif_t *hwif, if (ide_allocate_dma_engine(hwif)) return -1; - hwif->dma_ops = &sff_dma_ops; - return 0; } @@ -1426,6 +1424,7 @@ static const struct ide_dma_ops hpt37x_dma_ops = { .dma_test_irq = hpt374_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_dma_ops hpt370_dma_ops = { @@ -1437,6 +1436,7 @@ static const struct ide_dma_ops hpt370_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = hpt370_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_dma_ops hpt36x_dma_ops = { @@ -1448,6 +1448,7 @@ static const struct ide_dma_ops hpt36x_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = hpt366_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_port_info hpt366_chipsets[] __devinitdata = { diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 81f70caeb40f..97a35c667aee 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -166,7 +166,7 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = { */ static void icside_maskproc(ide_drive_t *drive, int mask) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct expansion_card *ec = ECARD_DEV(hwif->dev); struct icside_state *state = ecard_get_drvdata(ec); unsigned long flags; @@ -284,7 +284,7 @@ static void icside_dma_host_set(ide_drive_t *drive, int on) static int icside_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct expansion_card *ec = ECARD_DEV(hwif->dev); drive->waiting_for_dma = 0; @@ -299,7 +299,7 @@ static int icside_dma_end(ide_drive_t *drive) static void icside_dma_start(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct expansion_card *ec = ECARD_DEV(hwif->dev); /* We can not enable DMA on both channels simultaneously. */ @@ -309,10 +309,10 @@ static void icside_dma_start(ide_drive_t *drive) static int icside_dma_setup(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct expansion_card *ec = ECARD_DEV(hwif->dev); struct icside_state *state = ecard_get_drvdata(ec); - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; unsigned int dma_mode; if (rq_data_dir(rq)) @@ -362,7 +362,7 @@ static void icside_dma_exec_cmd(ide_drive_t *drive, u8 cmd) static int icside_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct expansion_card *ec = ECARD_DEV(hwif->dev); struct icside_state *state = ecard_get_drvdata(ec); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index fd4a36433050..2f9e941968d6 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -218,7 +218,7 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) */ static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; int port; acpi_handle drive_handle; @@ -263,7 +263,7 @@ static int do_drive_get_GTF(ide_drive_t *drive, acpi_status status; struct acpi_buffer output; union acpi_object *out_obj; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct device *dev = hwif->gendev.parent; int err = -ENODEV; int port; @@ -641,7 +641,8 @@ void ide_acpi_push_timing(ide_hwif_t *hwif) */ void ide_acpi_set_state(ide_hwif_t *hwif, int on) { - int unit; + ide_drive_t *drive; + int i; if (ide_noacpi || ide_noacpi_psx) return; @@ -655,9 +656,8 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on) /* channel first and then drives for power on and verse versa for power off */ if (on) acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; + ide_port_for_each_dev(i, drive, hwif) { if (!drive->acpidata->obj_handle) drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); @@ -711,15 +711,13 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif) * for both drives, regardless whether they are connected * or not. */ - hwif->drives[0].acpidata = &hwif->acpidata->master; - hwif->drives[1].acpidata = &hwif->acpidata->slave; + hwif->devices[0]->acpidata = &hwif->acpidata->master; + hwif->devices[1]->acpidata = &hwif->acpidata->slave; /* * Send IDENTIFY for each drive */ - for (i = 0; i < MAX_DRIVES; i++) { - drive = &hwif->drives[i]; - + ide_port_for_each_dev(i, drive, hwif) { memset(drive->acpidata, 0, sizeof(*drive->acpidata)); if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) @@ -744,9 +742,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif) ide_acpi_get_timing(hwif); ide_acpi_push_timing(hwif); - for (i = 0; i < MAX_DRIVES; i++) { - drive = &hwif->drives[i]; - + ide_port_for_each_dev(i, drive, hwif) { if (drive->dev_flags & IDE_DFLAG_PRESENT) /* Execute ACPI startup code */ ide_acpi_exec_tfs(drive); diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index e8688c0f8645..e96c01260598 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -243,7 +243,7 @@ EXPORT_SYMBOL_GPL(ide_retry_pc); int ide_cd_expiry(ide_drive_t *drive) { - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = drive->hwif->rq; unsigned long wait = 0; debug_log("%s: rq->cmd[0]: 0x%x\n", __func__, rq->cmd[0]); @@ -294,7 +294,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) { struct ide_atapi_pc *pc = drive->pc; ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; const struct ide_tp_ops *tp_ops = hwif->tp_ops; xfer_func_t *xferfunc; unsigned int timeout, temp; @@ -491,7 +491,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) { struct ide_atapi_pc *uninitialized_var(pc); ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; ide_expiry_t *expiry; unsigned int timeout; int cmd_len; @@ -549,7 +549,10 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) } /* Set the interrupt routine */ - ide_set_handler(drive, ide_pc_intr, timeout, expiry); + ide_set_handler(drive, + (dev_is_idecd(drive) ? drive->irq_handler + : ide_pc_intr), + timeout, expiry); /* Begin DMA, if necessary */ if (dev_is_idecd(drive)) { @@ -580,7 +583,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive) if (dev_is_idecd(drive)) { tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL; - bcount = ide_cd_get_xferlen(hwif->hwgroup->rq); + bcount = ide_cd_get_xferlen(hwif->rq); expiry = ide_cd_expiry; timeout = ATAPI_WAIT_PC; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 1a7410f88249..cae69372cf45 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -239,7 +239,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, static void cdrom_end_request(ide_drive_t *drive, int uptodate) { - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = drive->hwif->rq; int nsectors = rq->hard_cur_sectors; ide_debug_log(IDE_DBG_FUNC, "Call %s, cmd: 0x%x, uptodate: 0x%x, " @@ -306,8 +306,7 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st) static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; - struct request *rq = hwgroup->rq; + struct request *rq = hwif->rq; int stat, err, sense_key; /* check for errors */ @@ -502,7 +501,7 @@ end_request: blkdev_dequeue_request(rq); spin_unlock_irqrestore(q->queue_lock, flags); - hwgroup->rq = NULL; + hwif->rq = NULL; cdrom_queue_request_sense(drive, rq->sense, rq); } else @@ -511,106 +510,6 @@ end_request: return 1; } -static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *); -static ide_startstop_t cdrom_newpc_intr(ide_drive_t *); - -/* - * Set up the device registers for transferring a packet command on DEV, - * expecting to later transfer XFERLEN bytes. HANDLER is the routine - * which actually transfers the command to the drive. If this is a - * drq_interrupt device, this routine will arrange for HANDLER to be - * called when the interrupt from the drive arrives. Otherwise, HANDLER - * will be called immediately after the drive is prepared for the transfer. - */ -static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; - int xferlen; - - xferlen = ide_cd_get_xferlen(rq); - - ide_debug_log(IDE_DBG_PC, "Call %s, xferlen: %d\n", __func__, xferlen); - - /* FIXME: for Virtual DMA we must check harder */ - if (drive->dma) - drive->dma = !hwif->dma_ops->dma_setup(drive); - - /* set up the controller registers */ - ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL, - xferlen, drive->dma); - - if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { - /* waiting for CDB interrupt, not DMA yet. */ - if (drive->dma) - drive->waiting_for_dma = 0; - - /* packet command */ - ide_execute_command(drive, ATA_CMD_PACKET, - cdrom_transfer_packet_command, - ATAPI_WAIT_PC, ide_cd_expiry); - return ide_started; - } else { - ide_execute_pkt_cmd(drive); - - return cdrom_transfer_packet_command(drive); - } -} - -/* - * Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. The device - * registers must have already been prepared by cdrom_start_packet_command. - * HANDLER is the interrupt handler to call when the command completes or - * there's data ready. - */ -#define ATAPI_MIN_CDB_BYTES 12 -static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; - int cmd_len; - ide_startstop_t startstop; - - ide_debug_log(IDE_DBG_PC, "Call %s\n", __func__); - - if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { - /* - * Here we should have been called after receiving an interrupt - * from the device. DRQ should how be set. - */ - - /* check for errors */ - if (cdrom_decode_status(drive, ATA_DRQ, NULL)) - return ide_stopped; - - /* ok, next interrupt will be DMA interrupt */ - if (drive->dma) - drive->waiting_for_dma = 1; - } else { - /* otherwise, we must wait for DRQ to get set */ - if (ide_wait_stat(&startstop, drive, ATA_DRQ, - ATA_BUSY, WAIT_READY)) - return startstop; - } - - /* arm the interrupt handler */ - ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, ide_cd_expiry); - - /* ATAPI commands get padded out to 12 bytes minimum */ - cmd_len = COMMAND_SIZE(rq->cmd[0]); - if (cmd_len < ATAPI_MIN_CDB_BYTES) - cmd_len = ATAPI_MIN_CDB_BYTES; - - /* send the command to the device */ - hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); - - /* start the DMA if need be */ - if (drive->dma) - hwif->dma_ops->dma_start(drive); - - return ide_started; -} - /* * Check the contents of the interrupt reason register from the cdrom * and attempt to recover if there are problems. Returns 0 if everything's @@ -854,8 +753,7 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq) static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; - struct request *rq = hwgroup->rq; + struct request *rq = hwif->rq; xfer_func_t *xferfunc; ide_expiry_t *expiry = NULL; int dma_error = 0, dma, stat, thislen, uptodate = 0; @@ -1061,7 +959,7 @@ end_request: if (blk_end_request(rq, 0, dlen)) BUG(); - hwgroup->rq = NULL; + hwif->rq = NULL; } else { if (!uptodate) rq->cmd_flags |= REQ_FAILED; @@ -1183,7 +1081,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, return ide_stopped; } - return cdrom_start_packet_command(drive); + return ide_issue_pc(drive); } /* @@ -1916,7 +1814,7 @@ static void ide_cd_release(struct kref *kref) static int ide_cd_probe(ide_drive_t *); -static ide_driver_t ide_cdrom_driver = { +static struct ide_driver ide_cdrom_driver = { .gen_driver = { .owner = THIS_MODULE, .name = "ide-cdrom", @@ -1927,7 +1825,6 @@ static ide_driver_t ide_cdrom_driver = { .version = IDECD_VERSION, .do_request = ide_cd_do_request, .end_request = ide_end_request, - .error = __ide_error, #ifdef CONFIG_IDE_PROC_FS .proc_entries = ide_cd_proc_entries, .proc_devsets = ide_cd_proc_devsets, @@ -2082,6 +1979,7 @@ static int ide_cd_probe(ide_drive_t *drive) } drive->debug_mask = debug_mask; + drive->irq_handler = cdrom_newpc_intr; info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL); if (info == NULL) { diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index bf676b262181..ac40d6cb90a2 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -33,33 +33,33 @@ /* Structure of a MSF cdrom address. */ struct atapi_msf { - byte reserved; - byte minute; - byte second; - byte frame; + u8 reserved; + u8 minute; + u8 second; + u8 frame; }; /* Space to hold the disk TOC. */ #define MAX_TRACKS 99 struct atapi_toc_header { unsigned short toc_length; - byte first_track; - byte last_track; + u8 first_track; + u8 last_track; }; struct atapi_toc_entry { - byte reserved1; + u8 reserved1; #if defined(__BIG_ENDIAN_BITFIELD) - __u8 adr : 4; - __u8 control : 4; + u8 adr : 4; + u8 control : 4; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 control : 4; - __u8 adr : 4; + u8 control : 4; + u8 adr : 4; #else #error "Please fix <asm/byteorder.h>" #endif - byte track; - byte reserved2; + u8 track; + u8 reserved2; union { unsigned lba; struct atapi_msf msf; @@ -77,10 +77,10 @@ struct atapi_toc { /* Extra per-device info for cdrom drives. */ struct cdrom_info { - ide_drive_t *drive; - ide_driver_t *driver; - struct gendisk *disk; - struct kref kref; + ide_drive_t *drive; + struct ide_driver *driver; + struct gendisk *disk; + struct kref kref; /* Buffer for table of contents. NULL if we haven't allocated a TOC buffer for this device yet. */ diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index eb9fac4d0f0c..4088a622873e 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -89,7 +89,7 @@ static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma) static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u16 nsectors = (u16)rq->nr_sectors; u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); @@ -187,7 +187,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c index f6d2d44d8a9a..123d393658af 100644 --- a/drivers/ide/ide-dma-sff.c +++ b/drivers/ide/ide-dma-sff.c @@ -50,6 +50,27 @@ int config_drive_for_dma(ide_drive_t *drive) return 0; } +u8 ide_dma_sff_read_status(ide_hwif_t *hwif) +{ + unsigned long addr = hwif->dma_base + ATA_DMA_STATUS; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + return readb((void __iomem *)addr); + else + return inb(addr); +} +EXPORT_SYMBOL_GPL(ide_dma_sff_read_status); + +static void ide_dma_sff_write_status(ide_hwif_t *hwif, u8 val) +{ + unsigned long addr = hwif->dma_base + ATA_DMA_STATUS; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + writeb(val, (void __iomem *)addr); + else + outb(val, addr); +} + /** * ide_dma_host_set - Enable/disable DMA on a host * @drive: drive to control @@ -62,18 +83,14 @@ void ide_dma_host_set(ide_drive_t *drive, int on) { ide_hwif_t *hwif = drive->hwif; u8 unit = drive->dn & 1; - u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); if (on) dma_stat |= (1 << (5 + unit)); else dma_stat &= ~(1 << (5 + unit)); - if (hwif->host_flags & IDE_HFLAG_MMIO) - writeb(dma_stat, - (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)); - else - outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS); + ide_dma_sff_write_status(hwif, dma_stat); } EXPORT_SYMBOL_GPL(ide_dma_host_set); @@ -175,7 +192,7 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable); int ide_dma_setup(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; unsigned int reading = rq_data_dir(rq) ? 0 : ATA_DMA_WR; u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; u8 dma_stat; @@ -187,7 +204,7 @@ int ide_dma_setup(ide_drive_t *drive) } /* PRD table */ - if (hwif->host_flags & IDE_HFLAG_MMIO) + if (mmio) writel(hwif->dmatable_dma, (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS)); else @@ -200,15 +217,10 @@ int ide_dma_setup(ide_drive_t *drive) outb(reading, hwif->dma_base + ATA_DMA_CMD); /* read DMA status for INTR & ERROR flags */ - dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); /* clear INTR & ERROR flags */ - if (mmio) - writeb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR, - (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)); - else - outb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR, - hwif->dma_base + ATA_DMA_STATUS); + ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); drive->waiting_for_dma = 1; return 0; @@ -232,7 +244,7 @@ EXPORT_SYMBOL_GPL(ide_dma_setup); static int dma_timer_expiry(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n", drive->name, __func__, dma_stat); @@ -240,7 +252,7 @@ static int dma_timer_expiry(ide_drive_t *drive) if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */ return WAIT_CMD; - hwif->hwgroup->expiry = NULL; /* one free ride for now */ + hwif->expiry = NULL; /* one free ride for now */ if (dma_stat & ATA_DMA_ERR) /* ERROR */ return -1; @@ -289,13 +301,12 @@ EXPORT_SYMBOL_GPL(ide_dma_start); int ide_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; u8 dma_stat = 0, dma_cmd = 0, mask; drive->waiting_for_dma = 0; /* stop DMA */ - if (mmio) { + if (hwif->host_flags & IDE_HFLAG_MMIO) { dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); writeb(dma_cmd & ~ATA_DMA_START, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); @@ -305,15 +316,10 @@ int ide_dma_end(ide_drive_t *drive) } /* get DMA status */ - dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - if (mmio) - /* clear the INTR & ERROR bits */ - writeb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR, - (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)); - else - outb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR, - hwif->dma_base + ATA_DMA_STATUS); + /* clear INTR & ERROR bits */ + ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); /* purge DMA mappings */ ide_destroy_dmatable(drive); @@ -331,7 +337,7 @@ EXPORT_SYMBOL_GPL(ide_dma_end); int ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); return (dma_stat & ATA_DMA_INTR) ? 1 : 0; } @@ -346,5 +352,6 @@ const struct ide_dma_ops sff_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, + .dma_sff_read_status = ide_dma_sff_read_status, }; EXPORT_SYMBOL_GPL(sff_dma_ops); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index fffd11717b2d..72ebab0bc755 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -96,7 +96,7 @@ ide_startstop_t ide_dma_intr(ide_drive_t *drive) if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) { if (!dma_stat) { - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; task_end_request(drive, rq, stat); return ide_stopped; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 0a48e2dc53a2..3eab1c6c9b31 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -71,7 +71,7 @@ static int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs) { struct ide_disk_obj *floppy = drive->driver_data; - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = drive->hwif->rq; int error; ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__); diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index b8078b3231f7..7857b209c6df 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -149,7 +149,7 @@ static int ide_gd_end_request(ide_drive_t *drive, int uptodate, int nrsecs) return drive->disk_ops->end_request(drive, uptodate, nrsecs); } -static ide_driver_t ide_gd_driver = { +static struct ide_driver ide_gd_driver = { .gen_driver = { .owner = THIS_MODULE, .name = "ide-gd", @@ -162,7 +162,6 @@ static ide_driver_t ide_gd_driver = { .version = IDE_GD_VERSION, .do_request = ide_gd_do_request, .end_request = ide_gd_end_request, - .error = __ide_error, #ifdef CONFIG_IDE_PROC_FS .proc_entries = ide_disk_proc_entries, .proc_devsets = ide_disk_proc_devsets, diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h index 7d3d101713e0..a86779f0756b 100644 --- a/drivers/ide/ide-gd.h +++ b/drivers/ide/ide-gd.h @@ -14,11 +14,11 @@ #endif struct ide_disk_obj { - ide_drive_t *drive; - ide_driver_t *driver; - struct gendisk *disk; - struct kref kref; - unsigned int openers; /* protected by BKL for now */ + ide_drive_t *drive; + struct ide_driver *driver; + struct gendisk *disk; + struct kref kref; + unsigned int openers; /* protected by BKL for now */ /* Last failed packet command */ struct ide_atapi_pc *failed_pc; diff --git a/drivers/ide/ide-h8300.c b/drivers/ide/ide-h8300.c index e2cdd2e9cdec..9270d3255ee0 100644 --- a/drivers/ide/ide-h8300.c +++ b/drivers/ide/ide-h8300.c @@ -159,7 +159,6 @@ static const struct ide_tp_ops h8300_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 1c36a8e83d36..cc163319dfbd 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -88,7 +88,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, ret = 0; if (ret == 0 && dequeue) - drive->hwif->hwgroup->rq = NULL; + drive->hwif->rq = NULL; return ret; } @@ -107,7 +107,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) { unsigned int nr_bytes = nr_sectors << 9; - struct request *rq = drive->hwif->hwgroup->rq; + struct request *rq = drive->hwif->rq; if (!nr_bytes) { if (blk_pc_request(rq)) @@ -160,8 +160,8 @@ EXPORT_SYMBOL_GPL(ide_end_dequeued_request); void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) { - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; - struct request *rq = hwgroup->rq; + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *task = (ide_task_t *)rq->special; @@ -186,7 +186,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) return; } - hwgroup->rq = NULL; + hwif->rq = NULL; rq->errors = err; @@ -199,9 +199,9 @@ EXPORT_SYMBOL(ide_end_drive_cmd); static void ide_kill_rq(ide_drive_t *drive, struct request *rq) { if (rq->rq_disk) { - ide_driver_t *drv; + struct ide_driver *drv; - drv = *(ide_driver_t **)rq->rq_disk->private_data; + drv = *(struct ide_driver **)rq->rq_disk->private_data; drv->end_request(drive, 0, 0); } else ide_end_request(drive, 0, 0); @@ -291,7 +291,7 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u return ide_stopped; } -ide_startstop_t +static ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) { if (drive->media == ide_disk) @@ -299,8 +299,6 @@ __ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) return ide_atapi_error(drive, rq, stat, err); } -EXPORT_SYMBOL_GPL(__ide_error); - /** * ide_error - handle an error on the IDE * @drive: drive the error occurred on @@ -321,7 +319,8 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat) err = ide_dump_status(drive, msg, stat); - if ((rq = HWGROUP(drive)->rq) == NULL) + rq = drive->hwif->rq; + if (rq == NULL) return ide_stopped; /* retry only "normal" I/O: */ @@ -331,15 +330,8 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat) return ide_stopped; } - if (rq->rq_disk) { - ide_driver_t *drv; - - drv = *(ide_driver_t **)rq->rq_disk->private_data; - return drv->error(drive, rq, stat, err); - } else - return __ide_error(drive, rq, stat, err); + return __ide_error(drive, rq, stat, err); } - EXPORT_SYMBOL_GPL(ide_error); static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf) @@ -462,7 +454,7 @@ EXPORT_SYMBOL_GPL(ide_init_sg_cmd); static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; ide_task_t *task = rq->special; if (task) { @@ -586,7 +578,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) #ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", - HWIF(drive)->name, (unsigned long) rq); + drive->hwif->name, (unsigned long) rq); #endif /* bail early if we've exceeded max_failures */ @@ -605,7 +597,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) return startstop; } if (!drive->special.all) { - ide_driver_t *drv; + struct ide_driver *drv; /* * We reset the drive so we need to issue a SETFEATURES. @@ -638,7 +630,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) */ return ide_special_rq(drive, rq); - drv = *(ide_driver_t **)rq->rq_disk->private_data; + drv = *(struct ide_driver **)rq->rq_disk->private_data; return drv->do_request(drive, rq, rq->sector); } @@ -654,7 +646,7 @@ kill_rq: * @timeout: time to stall for (jiffies) * * ide_stall_queue() can be used by a drive to give excess bandwidth back - * to the hwgroup by sleeping for timeout jiffies. + * to the port by sleeping for timeout jiffies. */ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) @@ -666,45 +658,53 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) } EXPORT_SYMBOL(ide_stall_queue); +static inline int ide_lock_port(ide_hwif_t *hwif) +{ + if (hwif->busy) + return 1; + + hwif->busy = 1; + + return 0; +} + +static inline void ide_unlock_port(ide_hwif_t *hwif) +{ + hwif->busy = 0; +} + +static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif) +{ + int rc = 0; + + if (host->host_flags & IDE_HFLAG_SERIALIZE) { + rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy); + if (rc == 0) { + /* for atari only */ + ide_get_lock(ide_intr, hwif); + } + } + return rc; +} + +static inline void ide_unlock_host(struct ide_host *host) +{ + if (host->host_flags & IDE_HFLAG_SERIALIZE) { + /* for atari only */ + ide_release_lock(); + clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy); + } +} + /* - * Issue a new request to a drive from hwgroup - * - * A hwgroup is a serialized group of IDE interfaces. Usually there is - * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640) - * may have both interfaces in a single hwgroup to "serialize" access. - * Or possibly multiple ISA interfaces can share a common IRQ by being grouped - * together into one hwgroup for serialized access. - * - * Note also that several hwgroups can end up sharing a single IRQ, - * possibly along with many other devices. This is especially common in - * PCI-based systems with off-board IDE controller cards. - * - * The IDE driver uses a per-hwgroup lock to protect the hwgroup->busy flag. - * - * The first thread into the driver for a particular hwgroup sets the - * hwgroup->busy flag to indicate that this hwgroup is now active, - * and then initiates processing of the top request from the request queue. - * - * Other threads attempting entry notice the busy setting, and will simply - * queue their new requests and exit immediately. Note that hwgroup->busy - * remains set even when the driver is merely awaiting the next interrupt. - * Thus, the meaning is "this hwgroup is busy processing a request". - * - * When processing of a request completes, the completing thread or IRQ-handler - * will start the next request from the queue. If no more work remains, - * the driver will clear the hwgroup->busy flag and exit. - * - * The per-hwgroup spinlock is used to protect all access to the - * hwgroup->busy flag, but is otherwise not needed for most processing in - * the driver. This makes the driver much more friendlier to shared IRQs - * than previous designs, while remaining 100% (?) SMP safe and capable. + * Issue a new request to a device. */ void do_ide_request(struct request_queue *q) { ide_drive_t *drive = q->queuedata; ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; - struct request *rq; + struct ide_host *host = hwif->host; + struct request *rq = NULL; ide_startstop_t startstop; /* @@ -721,32 +721,40 @@ void do_ide_request(struct request_queue *q) blk_remove_plug(q); spin_unlock_irq(q->queue_lock); - spin_lock_irq(&hwgroup->lock); - if (!ide_lock_hwgroup(hwgroup)) { + if (ide_lock_host(host, hwif)) + goto plug_device_2; + + spin_lock_irq(&hwif->lock); + + if (!ide_lock_port(hwif)) { + ide_hwif_t *prev_port; repeat: - hwgroup->rq = NULL; + prev_port = hwif->host->cur_port; + hwif->rq = NULL; if (drive->dev_flags & IDE_DFLAG_SLEEPING) { if (time_before(drive->sleep, jiffies)) { - ide_unlock_hwgroup(hwgroup); + ide_unlock_port(hwif); goto plug_device; } } - if (hwif != hwgroup->hwif) { + if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) && + hwif != prev_port) { /* - * set nIEN for previous hwif, drives in the + * set nIEN for previous port, drives in the * quirk_list may not like intr setups/cleanups */ - if (drive->quirk_list == 0) - hwif->tp_ops->set_irq(hwif, 0); + if (prev_port && prev_port->cur_dev->quirk_list == 0) + prev_port->tp_ops->set_irq(prev_port, 0); + + hwif->host->cur_port = hwif; } - hwgroup->hwif = hwif; - hwgroup->drive = drive; + hwif->cur_dev = drive; drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED); - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); spin_lock_irq(q->queue_lock); /* * we know that the queue isn't empty, but this can happen @@ -754,10 +762,10 @@ repeat: */ rq = elv_next_request(drive->queue); spin_unlock_irq(q->queue_lock); - spin_lock_irq(&hwgroup->lock); + spin_lock_irq(&hwif->lock); if (!rq) { - ide_unlock_hwgroup(hwgroup); + ide_unlock_port(hwif); goto out; } @@ -778,27 +786,31 @@ repeat: blk_pm_request(rq) == 0 && (rq->cmd_flags & REQ_PREEMPT) == 0) { /* there should be no pending command at this point */ - ide_unlock_hwgroup(hwgroup); + ide_unlock_port(hwif); goto plug_device; } - hwgroup->rq = rq; + hwif->rq = rq; - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); startstop = start_request(drive, rq); - spin_lock_irq(&hwgroup->lock); + spin_lock_irq(&hwif->lock); if (startstop == ide_stopped) goto repeat; } else goto plug_device; out: - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); + if (rq == NULL) + ide_unlock_host(host); spin_lock_irq(q->queue_lock); return; plug_device: - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); + ide_unlock_host(host); +plug_device_2: spin_lock_irq(q->queue_lock); if (!elv_queue_empty(q)) @@ -806,13 +818,13 @@ plug_device: } /* - * un-busy the hwgroup etc, and clear any pending DMA status. we want to + * un-busy the port etc, and clear any pending DMA status. we want to * retry the current request in pio mode instead of risking tossing it * all away */ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct request *rq; ide_startstop_t ret = ide_stopped; @@ -840,15 +852,14 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) ide_dma_off_quietly(drive); /* - * un-busy drive etc (hwgroup->busy is cleared on return) and - * make sure request is sane + * un-busy drive etc and make sure request is sane */ - rq = HWGROUP(drive)->rq; + rq = hwif->rq; if (!rq) goto out; - HWGROUP(drive)->rq = NULL; + hwif->rq = NULL; rq->errors = 0; @@ -876,7 +887,7 @@ static void ide_plug_device(ide_drive_t *drive) /** * ide_timer_expiry - handle lack of an IDE interrupt - * @data: timer callback magic (hwgroup) + * @data: timer callback magic (hwif) * * An IDE command has timed out before the expected drive return * occurred. At this point we attempt to clean up the current @@ -890,18 +901,18 @@ static void ide_plug_device(ide_drive_t *drive) void ide_timer_expiry (unsigned long data) { - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; + ide_hwif_t *hwif = (ide_hwif_t *)data; ide_drive_t *uninitialized_var(drive); ide_handler_t *handler; - ide_expiry_t *expiry; unsigned long flags; unsigned long wait = -1; int plug_device = 0; - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); - if (((handler = hwgroup->handler) == NULL) || - (hwgroup->req_gen != hwgroup->req_gen_timer)) { + handler = hwif->handler; + + if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) { /* * Either a marginal timeout occurred * (got the interrupt just as timer expired), @@ -909,72 +920,68 @@ void ide_timer_expiry (unsigned long data) * Either way, we don't really want to complain about anything. */ } else { - drive = hwgroup->drive; - if (!drive) { - printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n"); - hwgroup->handler = NULL; - } else { - ide_hwif_t *hwif; - ide_startstop_t startstop = ide_stopped; - - if ((expiry = hwgroup->expiry) != NULL) { - /* continue */ - if ((wait = expiry(drive)) > 0) { - /* reset timer */ - hwgroup->timer.expires = jiffies + wait; - hwgroup->req_gen_timer = hwgroup->req_gen; - add_timer(&hwgroup->timer); - spin_unlock_irqrestore(&hwgroup->lock, flags); - return; - } - } - hwgroup->handler = NULL; - /* - * We need to simulate a real interrupt when invoking - * the handler() function, which means we need to - * globally mask the specific IRQ: - */ - spin_unlock(&hwgroup->lock); - hwif = HWIF(drive); - /* disable_irq_nosync ?? */ - disable_irq(hwif->irq); - /* local CPU only, - * as if we were handling an interrupt */ - local_irq_disable(); - if (hwgroup->polling) { - startstop = handler(drive); - } else if (drive_is_ready(drive)) { - if (drive->waiting_for_dma) - hwif->dma_ops->dma_lost_irq(drive); - (void)ide_ack_intr(hwif); - printk(KERN_WARNING "%s: lost interrupt\n", drive->name); - startstop = handler(drive); - } else { - if (drive->waiting_for_dma) { - startstop = ide_dma_timeout_retry(drive, wait); - } else - startstop = - ide_error(drive, "irq timeout", - hwif->tp_ops->read_status(hwif)); - } - spin_lock_irq(&hwgroup->lock); - enable_irq(hwif->irq); - if (startstop == ide_stopped) { - ide_unlock_hwgroup(hwgroup); - plug_device = 1; + ide_expiry_t *expiry = hwif->expiry; + ide_startstop_t startstop = ide_stopped; + + drive = hwif->cur_dev; + + if (expiry) { + wait = expiry(drive); + if (wait > 0) { /* continue */ + /* reset timer */ + hwif->timer.expires = jiffies + wait; + hwif->req_gen_timer = hwif->req_gen; + add_timer(&hwif->timer); + spin_unlock_irqrestore(&hwif->lock, flags); + return; } } + hwif->handler = NULL; + /* + * We need to simulate a real interrupt when invoking + * the handler() function, which means we need to + * globally mask the specific IRQ: + */ + spin_unlock(&hwif->lock); + /* disable_irq_nosync ?? */ + disable_irq(hwif->irq); + /* local CPU only, as if we were handling an interrupt */ + local_irq_disable(); + if (hwif->polling) { + startstop = handler(drive); + } else if (drive_is_ready(drive)) { + if (drive->waiting_for_dma) + hwif->dma_ops->dma_lost_irq(drive); + (void)ide_ack_intr(hwif); + printk(KERN_WARNING "%s: lost interrupt\n", + drive->name); + startstop = handler(drive); + } else { + if (drive->waiting_for_dma) + startstop = ide_dma_timeout_retry(drive, wait); + else + startstop = ide_error(drive, "irq timeout", + hwif->tp_ops->read_status(hwif)); + } + spin_lock_irq(&hwif->lock); + enable_irq(hwif->irq); + if (startstop == ide_stopped) { + ide_unlock_port(hwif); + plug_device = 1; + } } - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); - if (plug_device) + if (plug_device) { + ide_unlock_host(hwif->host); ide_plug_device(drive); + } } /** * unexpected_intr - handle an unexpected IDE interrupt * @irq: interrupt line - * @hwgroup: hwgroup being processed + * @hwif: port being processed * * There's nothing really useful we can do with an unexpected interrupt, * other than reading the status register (to clear it), and logging it. @@ -998,52 +1005,38 @@ void ide_timer_expiry (unsigned long data) * before completing the issuance of any new drive command, so we will not * be accidentally invoked as a result of any valid command completion * interrupt. - * - * Note that we must walk the entire hwgroup here. We know which hwif - * is doing the current command, but we don't know which hwif burped - * mysteriously. */ - -static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) -{ - u8 stat; - ide_hwif_t *hwif = hwgroup->hwif; - /* - * handle the unexpected interrupt - */ - do { - if (hwif->irq == irq) { - stat = hwif->tp_ops->read_status(hwif); - - if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { - /* Try to not flood the console with msgs */ - static unsigned long last_msgtime, count; - ++count; - if (time_after(jiffies, last_msgtime + HZ)) { - last_msgtime = jiffies; - printk(KERN_ERR "%s%s: unexpected interrupt, " - "status=0x%02x, count=%ld\n", - hwif->name, - (hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count); - } - } +static void unexpected_intr(int irq, ide_hwif_t *hwif) +{ + u8 stat = hwif->tp_ops->read_status(hwif); + + if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { + /* Try to not flood the console with msgs */ + static unsigned long last_msgtime, count; + ++count; + + if (time_after(jiffies, last_msgtime + HZ)) { + last_msgtime = jiffies; + printk(KERN_ERR "%s: unexpected interrupt, " + "status=0x%02x, count=%ld\n", + hwif->name, stat, count); } - } while ((hwif = hwif->next) != hwgroup->hwif); + } } /** * ide_intr - default IDE interrupt handler * @irq: interrupt number - * @dev_id: hwif group + * @dev_id: hwif * @regs: unused weirdness from the kernel irq layer * * This is the default IRQ handler for the IDE layer. You should * not need to override it. If you do be aware it is subtle in * places * - * hwgroup->hwif is the interface in the group currently performing - * a command. hwgroup->drive is the drive and hwgroup->handler is + * hwif is the interface in the group currently performing + * a command. hwif->cur_dev is the drive and hwif->handler is * the IRQ handler to call. As we issue a command the handlers * step through multiple states, reassigning the handler to the * next step in the process. Unlike a smart SCSI controller IDE @@ -1054,26 +1047,32 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) * * The handler eventually returns ide_stopped to indicate the * request completed. At this point we issue the next request - * on the hwgroup and the process begins again. + * on the port and the process begins again. */ - + irqreturn_t ide_intr (int irq, void *dev_id) { - unsigned long flags; - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; - ide_hwif_t *hwif = hwgroup->hwif; + ide_hwif_t *hwif = (ide_hwif_t *)dev_id; ide_drive_t *uninitialized_var(drive); ide_handler_t *handler; + unsigned long flags; ide_startstop_t startstop; irqreturn_t irq_ret = IRQ_NONE; int plug_device = 0; - spin_lock_irqsave(&hwgroup->lock, flags); + if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) { + if (hwif != hwif->host->cur_port) + goto out_early; + } + + spin_lock_irqsave(&hwif->lock, flags); if (!ide_ack_intr(hwif)) goto out; - if ((handler = hwgroup->handler) == NULL || hwgroup->polling) { + handler = hwif->handler; + + if (handler == NULL || hwif->polling) { /* * Not expecting an interrupt from this drive. * That means this could be: @@ -1097,7 +1096,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) * Probably not a shared PCI interrupt, * so we can safely try to do something about it: */ - unexpected_intr(irq, hwgroup); + unexpected_intr(irq, hwif); #ifdef CONFIG_BLK_DEV_IDEPCI } else { /* @@ -1110,16 +1109,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) goto out; } - drive = hwgroup->drive; - if (!drive) { - /* - * This should NEVER happen, and there isn't much - * we could do about it here. - * - * [Note - this can occur if the drive is hot unplugged] - */ - goto out_handled; - } + drive = hwif->cur_dev; if (!drive_is_ready(drive)) /* @@ -1131,10 +1121,10 @@ irqreturn_t ide_intr (int irq, void *dev_id) */ goto out; - hwgroup->handler = NULL; - hwgroup->req_gen++; - del_timer(&hwgroup->timer); - spin_unlock(&hwgroup->lock); + hwif->handler = NULL; + hwif->req_gen++; + del_timer(&hwif->timer); + spin_unlock(&hwif->lock); if (hwif->port_ops && hwif->port_ops->clear_irq) hwif->port_ops->clear_irq(drive); @@ -1145,7 +1135,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) /* service this interrupt, may set handler for next interrupt */ startstop = handler(drive); - spin_lock_irq(&hwgroup->lock); + spin_lock_irq(&hwif->lock); /* * Note that handler() may have set things up for another * interrupt to occur soon, but it cannot happen until @@ -1154,20 +1144,18 @@ irqreturn_t ide_intr (int irq, void *dev_id) * won't allow another of the same (on any CPU) until we return. */ if (startstop == ide_stopped) { - if (hwgroup->handler == NULL) { /* paranoia */ - ide_unlock_hwgroup(hwgroup); - plug_device = 1; - } else - printk(KERN_ERR "%s: %s: huh? expected NULL handler " - "on exit\n", __func__, drive->name); + BUG_ON(hwif->handler); + ide_unlock_port(hwif); + plug_device = 1; } -out_handled: irq_ret = IRQ_HANDLED; out: - spin_unlock_irqrestore(&hwgroup->lock, flags); - - if (plug_device) + spin_unlock_irqrestore(&hwif->lock, flags); +out_early: + if (plug_device) { + ide_unlock_host(hwif->host); ide_plug_device(drive); + } return irq_ret; } @@ -1189,15 +1177,13 @@ out: void ide_do_drive_cmd(ide_drive_t *drive, struct request *rq) { - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; struct request_queue *q = drive->queue; unsigned long flags; - hwgroup->rq = NULL; + drive->hwif->rq = NULL; spin_lock_irqsave(q->queue_lock, flags); __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); - blk_start_queueing(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(ide_do_drive_cmd); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index ad8bd6539283..e728cfe7273f 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -105,15 +105,6 @@ u8 ide_read_altstatus(ide_hwif_t *hwif) } EXPORT_SYMBOL_GPL(ide_read_altstatus); -u8 ide_read_sff_dma_status(ide_hwif_t *hwif) -{ - if (hwif->host_flags & IDE_HFLAG_MMIO) - return readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)); - else - return inb(hwif->dma_base + ATA_DMA_STATUS); -} -EXPORT_SYMBOL_GPL(ide_read_sff_dma_status); - void ide_set_irq(ide_hwif_t *hwif, int on) { u8 ctl = ATA_DEVCTL_OBS; @@ -388,7 +379,6 @@ const struct ide_tp_ops default_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, @@ -451,7 +441,7 @@ EXPORT_SYMBOL(ide_fixstring); */ int drive_is_ready (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u8 stat = 0; if (drive->waiting_for_dma) @@ -503,7 +493,8 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti stat = tp_ops->read_status(hwif); if (stat & ATA_BUSY) { - local_irq_set(flags); + local_irq_save(flags); + local_irq_enable_in_hardirq(); timeout += jiffies; while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) { if (time_after(jiffies, timeout)) { @@ -822,25 +813,25 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) static void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - - BUG_ON(hwgroup->handler); - hwgroup->handler = handler; - hwgroup->expiry = expiry; - hwgroup->timer.expires = jiffies + timeout; - hwgroup->req_gen_timer = hwgroup->req_gen; - add_timer(&hwgroup->timer); + ide_hwif_t *hwif = drive->hwif; + + BUG_ON(hwif->handler); + hwif->handler = handler; + hwif->expiry = expiry; + hwif->timer.expires = jiffies + timeout; + hwif->req_gen_timer = hwif->req_gen; + add_timer(&hwif->timer); } void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry) { - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; + ide_hwif_t *hwif = drive->hwif; unsigned long flags; - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); __ide_set_handler(drive, handler, timeout, expiry); - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); } EXPORT_SYMBOL(ide_set_handler); @@ -863,10 +854,9 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; unsigned long flags; - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); __ide_set_handler(drive, handler, timeout, expiry); hwif->tp_ops->exec_command(hwif, cmd); /* @@ -876,26 +866,25 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, * FIXME: we could skip this delay with care on non shared devices */ ndelay(400); - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); } EXPORT_SYMBOL(ide_execute_command); void ide_execute_pkt_cmd(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; unsigned long flags; - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET); ndelay(400); - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); } EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd); static inline void ide_complete_drive_reset(ide_drive_t *drive, int err) { - struct request *rq = drive->hwif->hwgroup->rq; + struct request *rq = drive->hwif->rq; if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET) ide_end_request(drive, err ? err : 1, 0); @@ -913,7 +902,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *, int); static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; u8 stat; SELECT_DRIVE(drive); @@ -923,20 +911,20 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive) if (OK_STAT(stat, 0, ATA_BUSY)) printk("%s: ATAPI reset complete\n", drive->name); else { - if (time_before(jiffies, hwgroup->poll_timeout)) { + if (time_before(jiffies, hwif->poll_timeout)) { ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); /* continue polling */ return ide_started; } /* end of polling */ - hwgroup->polling = 0; + hwif->polling = 0; printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat); /* do it the old fashioned way */ return do_reset1(drive, 1); } /* done polling */ - hwgroup->polling = 0; + hwif->polling = 0; ide_complete_drive_reset(drive, 0); return ide_stopped; } @@ -968,8 +956,7 @@ static void ide_reset_report_error(ide_hwif_t *hwif, u8 err) */ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_port_ops *port_ops = hwif->port_ops; u8 tmp; int err = 0; @@ -986,7 +973,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) tmp = hwif->tp_ops->read_status(hwif); if (!OK_STAT(tmp, 0, ATA_BUSY)) { - if (time_before(jiffies, hwgroup->poll_timeout)) { + if (time_before(jiffies, hwif->poll_timeout)) { ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL); /* continue polling */ return ide_started; @@ -1007,7 +994,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) } } out: - hwgroup->polling = 0; /* done polling */ + hwif->polling = 0; /* done polling */ ide_complete_drive_reset(drive, err); return ide_stopped; } @@ -1081,18 +1068,18 @@ static void pre_reset(ide_drive_t *drive) static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; struct ide_io_ports *io_ports = &hwif->io_ports; const struct ide_tp_ops *tp_ops = hwif->tp_ops; const struct ide_port_ops *port_ops; + ide_drive_t *tdrive; unsigned long flags, timeout; - unsigned int unit; + int i; DEFINE_WAIT(wait); - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); /* We must not reset with running handlers */ - BUG_ON(hwgroup->handler != NULL); + BUG_ON(hwif->handler != NULL); /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { @@ -1101,10 +1088,10 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) udelay (20); tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); ndelay(400); - hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - hwgroup->polling = 1; + hwif->poll_timeout = jiffies + WAIT_WORSTCASE; + hwif->polling = 1; __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); return ide_started; } @@ -1114,9 +1101,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE); timeout = jiffies; - for (unit = 0; unit < MAX_DRIVES; unit++) { - ide_drive_t *tdrive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, tdrive, hwif) { if (tdrive->dev_flags & IDE_DFLAG_PRESENT && tdrive->dev_flags & IDE_DFLAG_PARKED && time_after(tdrive->sleep, timeout)) @@ -1127,9 +1112,9 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) if (time_before_eq(timeout, now)) break; - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); timeout = schedule_timeout_uninterruptible(timeout - now); - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); } while (timeout); finish_wait(&ide_park_wq, &wait); @@ -1137,11 +1122,11 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) * First, reset any device state data we were maintaining * for any of the drives on this interface. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) - pre_reset(&hwif->drives[unit]); + ide_port_for_each_dev(i, tdrive, hwif) + pre_reset(tdrive); if (io_ports->ctl_addr == 0) { - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); ide_complete_drive_reset(drive, -ENXIO); return ide_stopped; } @@ -1164,8 +1149,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) tp_ops->set_irq(hwif, drive->quirk_list == 2); /* more than enough time */ udelay(10); - hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - hwgroup->polling = 1; + hwif->poll_timeout = jiffies + WAIT_WORSTCASE; + hwif->polling = 1; __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL); /* @@ -1177,7 +1162,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) if (port_ops && port_ops->resetproc) port_ops->resetproc(drive); - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); return ide_started; } @@ -1221,6 +1206,3 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) } return -EBUSY; } - -EXPORT_SYMBOL_GPL(ide_wait_not_busy); - diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 9f6e33d8a8b2..09526a0de734 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -273,7 +273,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) static void ide_dump_opcode(ide_drive_t *drive) { - struct request *rq = drive->hwif->hwgroup->rq; + struct request *rq = drive->hwif->rq; ide_task_t *task = NULL; if (!rq) @@ -346,10 +346,13 @@ static void ide_dump_ata_error(ide_drive_t *drive, u8 err) printk(KERN_CONT "}"); if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK || (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) { + struct request *rq = drive->hwif->rq; + ide_dump_sector(drive); - if (HWGROUP(drive) && HWGROUP(drive)->rq) + + if (rq) printk(KERN_CONT ", sector=%llu", - (unsigned long long)HWGROUP(drive)->rq->sector); + (unsigned long long)rq->sector); } printk(KERN_CONT "\n"); } diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index 678454ac2483..c875a957596c 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -7,22 +7,22 @@ DECLARE_WAIT_QUEUE_HEAD(ide_park_wq); static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) { - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; + ide_hwif_t *hwif = drive->hwif; struct request_queue *q = drive->queue; struct request *rq; int rc; timeout += jiffies; - spin_lock_irq(&hwgroup->lock); + spin_lock_irq(&hwif->lock); if (drive->dev_flags & IDE_DFLAG_PARKED) { int reset_timer = time_before(timeout, drive->sleep); int start_queue = 0; drive->sleep = timeout; wake_up_all(&ide_park_wq); - if (reset_timer && del_timer(&hwgroup->timer)) + if (reset_timer && del_timer(&hwif->timer)) start_queue = 1; - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); if (start_queue) { spin_lock_irq(q->queue_lock); @@ -31,7 +31,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) } return; } - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); rq = blk_get_request(q, READ, __GFP_WAIT); rq->cmd[0] = REQ_PARK_HEADS; @@ -64,21 +64,21 @@ ssize_t ide_park_show(struct device *dev, struct device_attribute *attr, char *buf) { ide_drive_t *drive = to_ide_device(dev); - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; + ide_hwif_t *hwif = drive->hwif; unsigned long now; unsigned int msecs; if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD) return -EOPNOTSUPP; - spin_lock_irq(&hwgroup->lock); + spin_lock_irq(&hwif->lock); now = jiffies; if (drive->dev_flags & IDE_DFLAG_PARKED && time_after(drive->sleep, now)) msecs = jiffies_to_msecs(drive->sleep - now); else msecs = 0; - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); return snprintf(buf, 20, "%u\n", msecs); } diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index 8282c6086e6a..4b3bf6a06b70 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -5,7 +5,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) { ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive); - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; ide_task_t args; @@ -39,7 +39,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) int generic_ide_resume(struct device *dev) { ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive); - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; ide_task_t args; @@ -67,7 +67,7 @@ int generic_ide_resume(struct device *dev) blk_put_request(rq); if (err == 0 && dev->driver) { - ide_driver_t *drv = to_ide_driver(dev->driver); + struct ide_driver *drv = to_ide_driver(dev->driver); if (drv->resume) drv->resume(drive); @@ -194,7 +194,7 @@ void ide_complete_pm_request(ide_drive_t *drive, struct request *rq) } spin_unlock_irqrestore(q->queue_lock, flags); - drive->hwif->hwgroup->rq = NULL; + drive->hwif->rq = NULL; if (blk_end_request(rq, 0, 0)) BUG(); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index c5adb7b9c5b5..0ccbb4459fb9 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -189,7 +189,7 @@ static void ide_classify_atapi_dev(ide_drive_t *drive) static void do_identify(ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u16 *id = drive->id; char *m = (char *)&id[ATA_ID_PROD]; unsigned long flags; @@ -266,7 +266,7 @@ err_misc: static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; const struct ide_tp_ops *tp_ops = hwif->tp_ops; int use_altstatus = 0, rc; @@ -341,7 +341,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) static int try_to_identify (ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; int retval; int autoprobe = 0; @@ -438,7 +438,7 @@ static u8 ide_read_device(ide_drive_t *drive) static int do_probe (ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; int rc; u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat; @@ -463,7 +463,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) if (ide_read_device(drive) != drive->select && present == 0) { if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(&hwif->drives[0]); + SELECT_DRIVE(hwif->devices[0]); /* allow ATA_BUSY to assert & clear */ msleep(50); } @@ -509,7 +509,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) } if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(&hwif->drives[0]); + SELECT_DRIVE(hwif->devices[0]); msleep(50); /* ensure drive irq is clear */ (void)tp_ops->read_status(hwif); @@ -522,7 +522,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) */ static void enable_nest (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; u8 stat; @@ -697,7 +697,8 @@ out: static int ide_port_wait_ready(ide_hwif_t *hwif) { - int unit, rc; + ide_drive_t *drive; + int i, rc; printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name); @@ -714,9 +715,7 @@ static int ide_port_wait_ready(ide_hwif_t *hwif) return rc; /* Now make sure both master & slave are ready */ - for (unit = 0; unit < MAX_DRIVES; unit++) { - ide_drive_t *drive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, drive, hwif) { /* Ignore disks that we will not probe for later. */ if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 || (drive->dev_flags & IDE_DFLAG_PRESENT)) { @@ -732,8 +731,8 @@ static int ide_port_wait_ready(ide_hwif_t *hwif) } out: /* Exit function with master reselected (let's be sane) */ - if (unit) - SELECT_DRIVE(&hwif->drives[0]); + if (i) + SELECT_DRIVE(hwif->devices[0]); return rc; } @@ -749,7 +748,7 @@ out: void ide_undecoded_slave(ide_drive_t *dev1) { - ide_drive_t *dev0 = &dev1->hwif->drives[0]; + ide_drive_t *dev0 = dev1->hwif->devices[0]; if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0) return; @@ -778,14 +777,15 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave); static int ide_probe_port(ide_hwif_t *hwif) { + ide_drive_t *drive; unsigned long flags; unsigned int irqd; - int unit, rc = -ENODEV; + int i, rc = -ENODEV; BUG_ON(hwif->present); - if ((hwif->drives[0].dev_flags & IDE_DFLAG_NOPROBE) && - (hwif->drives[1].dev_flags & IDE_DFLAG_NOPROBE)) + if ((hwif->devices[0]->dev_flags & IDE_DFLAG_NOPROBE) && + (hwif->devices[1]->dev_flags & IDE_DFLAG_NOPROBE)) return -EACCES; /* @@ -796,7 +796,8 @@ static int ide_probe_port(ide_hwif_t *hwif) if (irqd) disable_irq(hwif->irq); - local_irq_set(flags); + local_irq_save(flags); + local_irq_enable_in_hardirq(); if (ide_port_wait_ready(hwif) == -EBUSY) printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); @@ -805,9 +806,7 @@ static int ide_probe_port(ide_hwif_t *hwif) * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, drive, hwif) { (void) probe_for_drive(drive); if (drive->dev_flags & IDE_DFLAG_PRESENT) rc = 0; @@ -828,20 +827,17 @@ static int ide_probe_port(ide_hwif_t *hwif) static void ide_port_tune_devices(ide_hwif_t *hwif) { const struct ide_port_ops *port_ops = hwif->port_ops; - int unit; - - for (unit = 0; unit < MAX_DRIVES; unit++) { - ide_drive_t *drive = &hwif->drives[unit]; + ide_drive_t *drive; + int i; + ide_port_for_each_dev(i, drive, hwif) { if (drive->dev_flags & IDE_DFLAG_PRESENT) { if (port_ops && port_ops->quirkproc) port_ops->quirkproc(drive); } } - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, drive, hwif) { if (drive->dev_flags & IDE_DFLAG_PRESENT) { ide_set_max_pio(drive); @@ -852,11 +848,8 @@ static void ide_port_tune_devices(ide_hwif_t *hwif) } } - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - if ((hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) || - drive->id[ATA_ID_DWORD_IO]) + ide_port_for_each_dev(i, drive, hwif) { + if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT; else drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT; @@ -869,7 +862,7 @@ static void ide_port_tune_devices(ide_hwif_t *hwif) static int ide_init_queue(ide_drive_t *drive) { struct request_queue *q; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; int max_sectors = 256; int max_sg_entries = PRD_ENTRIES; @@ -918,36 +911,19 @@ static int ide_init_queue(ide_drive_t *drive) return 0; } -static void ide_add_drive_to_hwgroup(ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; - - spin_lock_irq(&hwgroup->lock); - if (!hwgroup->drive) { - /* first drive for hwgroup. */ - drive->next = drive; - hwgroup->drive = drive; - hwgroup->hwif = HWIF(hwgroup->drive); - } else { - drive->next = hwgroup->drive->next; - hwgroup->drive->next = drive; - } - spin_unlock_irq(&hwgroup->lock); -} +static DEFINE_MUTEX(ide_cfg_mtx); /* * For any present drive: * - allocate the block device queue - * - link drive into the hwgroup */ static int ide_port_setup_devices(ide_hwif_t *hwif) { + ide_drive_t *drive; int i, j = 0; mutex_lock(&ide_cfg_mtx); - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; - + ide_port_for_each_dev(i, drive, hwif) { if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) continue; @@ -961,139 +937,39 @@ static int ide_port_setup_devices(ide_hwif_t *hwif) } j++; - - ide_add_drive_to_hwgroup(drive); } mutex_unlock(&ide_cfg_mtx); return j; } -static ide_hwif_t *ide_ports[MAX_HWIFS]; - -void ide_remove_port_from_hwgroup(ide_hwif_t *hwif) -{ - ide_hwgroup_t *hwgroup = hwif->hwgroup; - - ide_ports[hwif->index] = NULL; - - spin_lock_irq(&hwgroup->lock); - /* - * Remove us from the hwgroup, and free - * the hwgroup if we were the only member - */ - if (hwif->next == hwif) { - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - /* There is another interface in hwgroup. - * Unlink us, and set hwgroup->drive and ->hwif to - * something sane. - */ - ide_hwif_t *g = hwgroup->hwif; - - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Chose a random hwif for hwgroup->hwif. - * It's guaranteed that there are no drives - * left in the hwgroup. - */ - BUG_ON(hwgroup->drive != NULL); - hwgroup->hwif = g; - } - BUG_ON(hwgroup->hwif == hwif); - } - spin_unlock_irq(&hwgroup->lock); -} - /* - * This routine sets up the irq for an ide interface, and creates a new - * hwgroup for the irq/hwif if none was previously assigned. - * - * Much of the code is for correctly detecting/handling irq sharing - * and irq serialization situations. This is somewhat complex because - * it handles static as well as dynamic (PCMCIA) IDE interfaces. + * This routine sets up the IRQ for an IDE interface. */ static int init_irq (ide_hwif_t *hwif) { struct ide_io_ports *io_ports = &hwif->io_ports; - unsigned int index; - ide_hwgroup_t *hwgroup; - ide_hwif_t *match = NULL; + int sa = 0; mutex_lock(&ide_cfg_mtx); - hwif->hwgroup = NULL; + spin_lock_init(&hwif->lock); - for (index = 0; index < MAX_HWIFS; index++) { - ide_hwif_t *h = ide_ports[index]; + init_timer(&hwif->timer); + hwif->timer.function = &ide_timer_expiry; + hwif->timer.data = (unsigned long)hwif; - if (h && h->hwgroup) { /* scan only initialized ports */ - if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) { - if (hwif->host == h->host) - match = h; - } - } - } - - /* - * If we are still without a hwgroup, then form a new one - */ - if (match) { - hwgroup = match->hwgroup; - hwif->hwgroup = hwgroup; - /* - * Link us into the hwgroup. - * This must be done early, do ensure that unexpected_intr - * can find the hwif and prevent irq storms. - * No drives are attached to the new hwif, choose_drive - * can't do anything stupid (yet). - * Add ourself as the 2nd entry to the hwgroup->hwif - * linked list, the first entry is the hwif that owns - * hwgroup->handler - do not change that. - */ - spin_lock_irq(&hwgroup->lock); - hwif->next = hwgroup->hwif->next; - hwgroup->hwif->next = hwif; - BUG_ON(hwif->next == hwif); - spin_unlock_irq(&hwgroup->lock); - } else { - hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO, - hwif_to_node(hwif)); - if (hwgroup == NULL) - goto out_up; - - spin_lock_init(&hwgroup->lock); - - hwif->hwgroup = hwgroup; - hwgroup->hwif = hwif->next = hwif; - - init_timer(&hwgroup->timer); - hwgroup->timer.function = &ide_timer_expiry; - hwgroup->timer.data = (unsigned long) hwgroup; - } - - ide_ports[hwif->index] = hwif; - - /* - * Allocate the irq, if not already obtained for another hwif - */ - if (!match || match->irq != hwif->irq) { - int sa = 0; #if defined(__mc68000__) - sa = IRQF_SHARED; + sa = IRQF_SHARED; #endif /* __mc68000__ */ - if (hwif->chipset == ide_pci) - sa = IRQF_SHARED; + if (hwif->chipset == ide_pci) + sa = IRQF_SHARED; - if (io_ports->ctl_addr) - hwif->tp_ops->set_irq(hwif, 1); + if (io_ports->ctl_addr) + hwif->tp_ops->set_irq(hwif, 1); - if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) - goto out_unlink; - } + if (request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwif)) + goto out_up; if (!hwif->rqsize) { if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) || @@ -1111,14 +987,12 @@ static int init_irq (ide_hwif_t *hwif) printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name, io_ports->data_addr, hwif->irq); #endif /* __mc68000__ */ - if (match) - printk(KERN_CONT " (serialized with %s)", match->name); + if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) + printk(KERN_CONT " (serialized)"); printk(KERN_CONT "\n"); mutex_unlock(&ide_cfg_mtx); return 0; -out_unlink: - ide_remove_port_from_hwgroup(hwif); out_up: mutex_unlock(&ide_cfg_mtx); return 1; @@ -1134,7 +1008,7 @@ static struct kobject *ata_probe(dev_t dev, int *part, void *data) { ide_hwif_t *hwif = data; int unit = *part >> PARTN_BITS; - ide_drive_t *drive = &hwif->drives[unit]; + ide_drive_t *drive = hwif->devices[unit]; if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) return NULL; @@ -1196,47 +1070,23 @@ void ide_init_disk(struct gendisk *disk, ide_drive_t *drive) EXPORT_SYMBOL_GPL(ide_init_disk); -static void ide_remove_drive_from_hwgroup(ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; - - if (drive == drive->next) { - /* special case: last drive from hwgroup. */ - BUG_ON(hwgroup->drive != drive); - hwgroup->drive = NULL; - } else { - ide_drive_t *walk; - - walk = hwgroup->drive; - while (walk->next != drive) - walk = walk->next; - walk->next = drive->next; - if (hwgroup->drive == drive) { - hwgroup->drive = drive->next; - hwgroup->hwif = hwgroup->drive->hwif; - } - } - BUG_ON(hwgroup->drive == drive); -} - static void drive_release_dev (struct device *dev) { ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; + ide_hwif_t *hwif = drive->hwif; ide_proc_unregister_device(drive); - spin_lock_irq(&hwgroup->lock); - ide_remove_drive_from_hwgroup(drive); + spin_lock_irq(&hwif->lock); kfree(drive->id); drive->id = NULL; drive->dev_flags &= ~IDE_DFLAG_PRESENT; /* Messed up locking ... */ - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); blk_cleanup_queue(drive->queue); - spin_lock_irq(&hwgroup->lock); + spin_lock_irq(&hwif->lock); drive->queue = NULL; - spin_unlock_irq(&hwgroup->lock); + spin_unlock_irq(&hwif->lock); complete(&drive->gendev_rel_comp); } @@ -1302,10 +1152,10 @@ out: static void hwif_register_devices(ide_hwif_t *hwif) { + ide_drive_t *drive; unsigned int i; - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; + ide_port_for_each_dev(i, drive, hwif) { struct device *dev = &drive->gendev; int ret; @@ -1328,11 +1178,10 @@ static void hwif_register_devices(ide_hwif_t *hwif) static void ide_port_init_devices(ide_hwif_t *hwif) { const struct ide_port_ops *port_ops = hwif->port_ops; + ide_drive_t *drive; int i; - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; - + ide_port_for_each_dev(i, drive, hwif) { drive->dn = i + hwif->channel * 2; if (hwif->host_flags & IDE_HFLAG_IO_32BIT) @@ -1380,6 +1229,8 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) { int rc; + hwif->dma_ops = d->dma_ops; + if (d->init_dma) rc = d->init_dma(hwif, d); else @@ -1387,12 +1238,13 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, if (rc < 0) { printk(KERN_INFO "%s: DMA disabled\n", hwif->name); + + hwif->dma_ops = NULL; hwif->dma_base = 0; hwif->swdma_mask = 0; hwif->mwdma_mask = 0; hwif->ultra_mask = 0; - } else if (d->dma_ops) - hwif->dma_ops = d->dma_ops; + } } if ((d->host_flags & IDE_HFLAG_SERIALIZE) || @@ -1417,6 +1269,66 @@ static void ide_port_cable_detect(ide_hwif_t *hwif) } } +static const u8 ide_hwif_to_major[] = + { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, + IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; + +static void ide_port_init_devices_data(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + u8 j = (hwif->index * MAX_DRIVES) + i; + + memset(drive, 0, sizeof(*drive)); + + drive->media = ide_disk; + drive->select = (i << 4) | ATA_DEVICE_OBS; + drive->hwif = hwif; + drive->ready_stat = ATA_DRDY; + drive->bad_wstat = BAD_W_STAT; + drive->special.b.recalibrate = 1; + drive->special.b.set_geometry = 1; + drive->name[0] = 'h'; + drive->name[1] = 'd'; + drive->name[2] = 'a' + j; + drive->max_failures = IDE_DEFAULT_MAX_FAILURES; + + INIT_LIST_HEAD(&drive->list); + init_completion(&drive->gendev_rel_comp); + } +} + +static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) +{ + /* fill in any non-zero initial values */ + hwif->index = index; + hwif->major = ide_hwif_to_major[index]; + + hwif->name[0] = 'i'; + hwif->name[1] = 'd'; + hwif->name[2] = 'e'; + hwif->name[3] = '0' + index; + + init_completion(&hwif->gendev_rel_comp); + + hwif->tp_ops = &default_tp_ops; + + ide_port_init_devices_data(hwif); +} + +static void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) +{ + memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports)); + hwif->irq = hw->irq; + hwif->chipset = hw->chipset; + hwif->dev = hw->dev; + hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; + hwif->ack_intr = hw->ack_intr; + hwif->config_data = hw->config; +} + static unsigned int ide_indexes; /** @@ -1466,12 +1378,43 @@ static void ide_free_port_slot(int idx) mutex_unlock(&ide_cfg_mtx); } +static void ide_port_free_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) + kfree(drive); +} + +static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) +{ + int i; + + for (i = 0; i < MAX_DRIVES; i++) { + ide_drive_t *drive; + + drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node); + if (drive == NULL) + goto out_nomem; + + hwif->devices[i] = drive; + } + return 0; + +out_nomem: + ide_port_free_devices(hwif); + return -ENOMEM; +} + struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) { struct ide_host *host; + struct device *dev = hws[0] ? hws[0]->dev : NULL; + int node = dev ? dev_to_node(dev) : -1; int i; - host = kzalloc(sizeof(*host), GFP_KERNEL); + host = kzalloc_node(sizeof(*host), GFP_KERNEL, node); if (host == NULL) return NULL; @@ -1482,10 +1425,15 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) if (hws[i] == NULL) continue; - hwif = kzalloc(sizeof(*hwif), GFP_KERNEL); + hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node); if (hwif == NULL) continue; + if (ide_port_alloc_devices(hwif, node) < 0) { + kfree(hwif); + continue; + } + idx = ide_find_port_slot(d); if (idx < 0) { printk(KERN_ERR "%s: no free slot for interface\n", @@ -1507,8 +1455,7 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) return NULL; } - if (hws[0]) - host->dev[0] = hws[0]->dev; + host->dev[0] = dev; if (d) { host->init_chipset = d->init_chipset; @@ -1525,9 +1472,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_hwif_t *hwif, *mate = NULL; int i, j = 0; - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) { mate = NULL; continue; @@ -1553,9 +1498,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_port_init_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1570,9 +1513,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_port_tune_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1597,9 +1538,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_acpi_port_init_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1607,9 +1546,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, hwif_register_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1647,17 +1584,85 @@ int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws, } EXPORT_SYMBOL_GPL(ide_host_add); +static void __ide_port_unregister_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + if (drive->dev_flags & IDE_DFLAG_PRESENT) { + device_unregister(&drive->gendev); + wait_for_completion(&drive->gendev_rel_comp); + } + } +} + +void ide_port_unregister_devices(ide_hwif_t *hwif) +{ + mutex_lock(&ide_cfg_mtx); + __ide_port_unregister_devices(hwif); + hwif->present = 0; + ide_port_init_devices_data(hwif); + mutex_unlock(&ide_cfg_mtx); +} +EXPORT_SYMBOL_GPL(ide_port_unregister_devices); + +/** + * ide_unregister - free an IDE interface + * @hwif: IDE interface + * + * Perform the final unregister of an IDE interface. + * + * Locking: + * The caller must not hold the IDE locks. + * + * It is up to the caller to be sure there is no pending I/O here, + * and that the interface will not be reopened (present/vanishing + * locking isn't yet done BTW). + */ + +static void ide_unregister(ide_hwif_t *hwif) +{ + BUG_ON(in_interrupt()); + BUG_ON(irqs_disabled()); + + mutex_lock(&ide_cfg_mtx); + + if (hwif->present) { + __ide_port_unregister_devices(hwif); + hwif->present = 0; + } + + ide_proc_unregister_port(hwif); + + free_irq(hwif->irq, hwif); + + device_unregister(hwif->portdev); + device_unregister(&hwif->gendev); + wait_for_completion(&hwif->gendev_rel_comp); + + /* + * Remove us from the kernel's knowledge + */ + blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS); + kfree(hwif->sg_table); + unregister_blkdev(hwif->major, hwif->name); + + ide_release_dma_engine(hwif); + + mutex_unlock(&ide_cfg_mtx); +} + void ide_host_free(struct ide_host *host) { ide_hwif_t *hwif; int i; - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; + ide_port_free_devices(hwif); ide_free_port_slot(hwif->index); kfree(hwif); } @@ -1668,11 +1673,12 @@ EXPORT_SYMBOL_GPL(ide_host_free); void ide_host_remove(struct ide_host *host) { + ide_hwif_t *hwif; int i; - for (i = 0; i < MAX_HOST_PORTS; i++) { - if (host->ports[i]) - ide_unregister(host->ports[i]); + ide_host_for_each_port(i, hwif, host) { + if (hwif) + ide_unregister(hwif); } ide_host_free(host); @@ -1691,8 +1697,8 @@ void ide_port_scan(ide_hwif_t *hwif) hwif->present = 1; ide_port_tune_devices(hwif); - ide_acpi_port_init_devices(hwif); ide_port_setup_devices(hwif); + ide_acpi_port_init_devices(hwif); hwif_register_devices(hwif); ide_proc_port_register_devices(hwif); } diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index a14e2938e4f3..1d8978b3314a 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -439,13 +439,13 @@ static int proc_ide_read_dmodel static int proc_ide_read_driver (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - struct device *dev = &drive->gendev; - ide_driver_t *ide_drv; - int len; + ide_drive_t *drive = (ide_drive_t *)data; + struct device *dev = &drive->gendev; + struct ide_driver *ide_drv; + int len; if (dev->driver) { - ide_drv = container_of(dev->driver, ide_driver_t, gen_driver); + ide_drv = to_ide_driver(dev->driver); len = sprintf(page, "%s version %s\n", dev->driver->name, ide_drv->version); } else @@ -555,7 +555,7 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t } } -void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) +void ide_proc_register_driver(ide_drive_t *drive, struct ide_driver *driver) { mutex_lock(&ide_setting_mtx); drive->settings = driver->proc_devsets(drive); @@ -577,7 +577,7 @@ EXPORT_SYMBOL(ide_proc_register_driver); * Takes ide_setting_mtx. */ -void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) +void ide_proc_unregister_driver(ide_drive_t *drive, struct ide_driver *driver) { ide_remove_proc_entries(drive->proc, driver->proc_entries(drive)); @@ -593,14 +593,13 @@ EXPORT_SYMBOL(ide_proc_unregister_driver); void ide_proc_port_register_devices(ide_hwif_t *hwif) { - int d; struct proc_dir_entry *ent; struct proc_dir_entry *parent = hwif->proc; + ide_drive_t *drive; char name[64]; + int i; - for (d = 0; d < MAX_DRIVES; d++) { - ide_drive_t *drive = &hwif->drives[d]; - + ide_port_for_each_dev(i, drive, hwif) { if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0 || drive->proc) continue; @@ -653,7 +652,7 @@ void ide_proc_unregister_port(ide_hwif_t *hwif) static int proc_print_driver(struct device_driver *drv, void *data) { - ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver); + struct ide_driver *ide_drv = to_ide_driver(drv); struct seq_file *s = data; seq_printf(s, "%s version %s\n", drv->name, ide_drv->version); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 5d2aa22cd6e4..d7ecd3c79757 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -166,10 +166,10 @@ struct idetape_bh { * to an interrupt or a timer event is stored in the struct defined below. */ typedef struct ide_tape_obj { - ide_drive_t *drive; - ide_driver_t *driver; - struct gendisk *disk; - struct kref kref; + ide_drive_t *drive; + struct ide_driver *driver; + struct gendisk *disk; + struct kref kref; /* * failed_pc points to the last failed packet command, or contains @@ -479,7 +479,7 @@ static void ide_tape_kfree_buffer(idetape_tape_t *tape) static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) { - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = drive->hwif->rq; idetape_tape_t *tape = drive->driver_data; unsigned long flags; int error; @@ -531,7 +531,7 @@ static void ide_tape_callback(ide_drive_t *drive, int dsc) printk(KERN_ERR "ide-tape: Error in REQUEST SENSE " "itself - Aborting request!\n"); } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { - struct request *rq = drive->hwif->hwgroup->rq; + struct request *rq = drive->hwif->rq; int blocks = pc->xferred / tape->blk_size; tape->avg_size += blocks * tape->blk_size; @@ -576,7 +576,7 @@ static void ide_tape_callback(ide_drive_t *drive, int dsc) /* * Postpone the current request so that ide.c will be able to service requests - * from another device on the same hwgroup while we are polling for DSC. + * from another device on the same port while we are polling for DSC. */ static void idetape_postpone_request(ide_drive_t *drive) { @@ -584,7 +584,8 @@ static void idetape_postpone_request(ide_drive_t *drive) debug_log(DBG_PROCS, "Enter %s\n", __func__); - tape->postponed_rq = HWGROUP(drive)->rq; + tape->postponed_rq = drive->hwif->rq; + ide_stall_queue(drive, tape->dsc_poll_freq); } @@ -2312,7 +2313,7 @@ static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive) static int ide_tape_probe(ide_drive_t *); -static ide_driver_t idetape_driver = { +static struct ide_driver idetape_driver = { .gen_driver = { .owner = THIS_MODULE, .name = "ide-tape", @@ -2323,7 +2324,6 @@ static ide_driver_t idetape_driver = { .version = IDETAPE_VERSION, .do_request = idetape_do_request, .end_request = idetape_end_request, - .error = __ide_error, #ifdef CONFIG_IDE_PROC_FS .proc_entries = ide_tape_proc_entries, .proc_devsets = ide_tape_proc_devsets, diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index bf4fb9d8d176..16138bce84a7 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -58,7 +58,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *); ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct ide_taskfile *tf = &task->tf; ide_handler_t *handler = NULL; const struct ide_tp_ops *tp_ops = hwif->tp_ops; @@ -309,9 +309,9 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, } if (sectors > 0) { - ide_driver_t *drv; + struct ide_driver *drv; - drv = *(ide_driver_t **)rq->rq_disk->private_data; + drv = *(struct ide_driver **)rq->rq_disk->private_data; drv->end_request(drive, 1, sectors); } } @@ -328,9 +328,9 @@ void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) } if (rq->rq_disk) { - ide_driver_t *drv; + struct ide_driver *drv; - drv = *(ide_driver_t **)rq->rq_disk->private_data;; + drv = *(struct ide_driver **)rq->rq_disk->private_data;; drv->end_request(drive, 1, rq->nr_sectors); } else ide_end_request(drive, 1, rq->nr_sectors); @@ -361,7 +361,7 @@ static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq static ide_startstop_t task_in_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; u8 stat = hwif->tp_ops->read_status(hwif); /* Error? */ @@ -395,7 +395,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive) static ide_startstop_t task_out_intr (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = hwif->rq; u8 stat = hwif->tp_ops->read_status(hwif); if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 46a2d4ca812b..258805da15c3 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -60,179 +60,8 @@ #include <linux/completion.h> #include <linux/device.h> - -/* default maximum number of failures */ -#define IDE_DEFAULT_MAX_FAILURES 1 - struct class *ide_port_class; -static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, - IDE2_MAJOR, IDE3_MAJOR, - IDE4_MAJOR, IDE5_MAJOR, - IDE6_MAJOR, IDE7_MAJOR, - IDE8_MAJOR, IDE9_MAJOR }; - -DEFINE_MUTEX(ide_cfg_mtx); - -static void ide_port_init_devices_data(ide_hwif_t *); - -/* - * Do not even *think* about calling this! - */ -void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) -{ - /* bulk initialize hwif & drive info with zeros */ - memset(hwif, 0, sizeof(ide_hwif_t)); - - /* fill in any non-zero initial values */ - hwif->index = index; - hwif->major = ide_hwif_to_major[index]; - - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; - hwif->name[2] = 'e'; - hwif->name[3] = '0' + index; - - init_completion(&hwif->gendev_rel_comp); - - hwif->tp_ops = &default_tp_ops; - - ide_port_init_devices_data(hwif); -} - -static void ide_port_init_devices_data(ide_hwif_t *hwif) -{ - int unit; - - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - u8 j = (hwif->index * MAX_DRIVES) + unit; - - memset(drive, 0, sizeof(*drive)); - - drive->media = ide_disk; - drive->select = (unit << 4) | ATA_DEVICE_OBS; - drive->hwif = hwif; - drive->ready_stat = ATA_DRDY; - drive->bad_wstat = BAD_W_STAT; - drive->special.b.recalibrate = 1; - drive->special.b.set_geometry = 1; - drive->name[0] = 'h'; - drive->name[1] = 'd'; - drive->name[2] = 'a' + j; - drive->max_failures = IDE_DEFAULT_MAX_FAILURES; - - INIT_LIST_HEAD(&drive->list); - init_completion(&drive->gendev_rel_comp); - } -} - -static void __ide_port_unregister_devices(ide_hwif_t *hwif) -{ - int i; - - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; - - if (drive->dev_flags & IDE_DFLAG_PRESENT) { - device_unregister(&drive->gendev); - wait_for_completion(&drive->gendev_rel_comp); - } - } -} - -void ide_port_unregister_devices(ide_hwif_t *hwif) -{ - mutex_lock(&ide_cfg_mtx); - __ide_port_unregister_devices(hwif); - hwif->present = 0; - ide_port_init_devices_data(hwif); - mutex_unlock(&ide_cfg_mtx); -} -EXPORT_SYMBOL_GPL(ide_port_unregister_devices); - -/** - * ide_unregister - free an IDE interface - * @hwif: IDE interface - * - * Perform the final unregister of an IDE interface. At the moment - * we don't refcount interfaces so this will also get split up. - * - * Locking: - * The caller must not hold the IDE locks - * The drive present/vanishing is not yet properly locked - * Take care with the callbacks. These have been split to avoid - * deadlocking the IDE layer. The shutdown callback is called - * before we take the lock and free resources. It is up to the - * caller to be sure there is no pending I/O here, and that - * the interface will not be reopened (present/vanishing locking - * isn't yet done BTW). After we commit to the final kill we - * call the cleanup callback with the ide locks held. - * - * Unregister restores the hwif structures to the default state. - * This is raving bonkers. - */ - -void ide_unregister(ide_hwif_t *hwif) -{ - ide_hwif_t *g; - ide_hwgroup_t *hwgroup; - int irq_count = 0; - - BUG_ON(in_interrupt()); - BUG_ON(irqs_disabled()); - - mutex_lock(&ide_cfg_mtx); - - if (hwif->present) { - __ide_port_unregister_devices(hwif); - hwif->present = 0; - } - - ide_proc_unregister_port(hwif); - - hwgroup = hwif->hwgroup; - /* - * free the irq if we were the only hwif using it - */ - g = hwgroup->hwif; - do { - if (g->irq == hwif->irq) - ++irq_count; - g = g->next; - } while (g != hwgroup->hwif); - if (irq_count == 1) - free_irq(hwif->irq, hwgroup); - - ide_remove_port_from_hwgroup(hwif); - - device_unregister(hwif->portdev); - device_unregister(&hwif->gendev); - wait_for_completion(&hwif->gendev_rel_comp); - - /* - * Remove us from the kernel's knowledge - */ - blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS); - kfree(hwif->sg_table); - unregister_blkdev(hwif->major, hwif->name); - - ide_release_dma_engine(hwif); - - mutex_unlock(&ide_cfg_mtx); -} - -void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) -{ - memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports)); - hwif->irq = hw->irq; - hwif->chipset = hw->chipset; - hwif->dev = hw->dev; - hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; - hwif->ack_intr = hw->ack_intr; - hwif->config_data = hw->config; -} - /* * Locks for IDE setting functionality */ @@ -330,7 +159,6 @@ static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) static int set_pio_mode(ide_drive_t *drive, int arg) { ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *hwgroup = hwif->hwgroup; const struct ide_port_ops *port_ops = hwif->port_ops; if (arg < 0 || arg > 255) @@ -345,9 +173,9 @@ static int set_pio_mode(ide_drive_t *drive, int arg) unsigned long flags; /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ - spin_lock_irqsave(&hwgroup->lock, flags); + spin_lock_irqsave(&hwif->lock, flags); port_ops->set_pio_mode(drive, arg); - spin_unlock_irqrestore(&hwgroup->lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); } else port_ops->set_pio_mode(drive, arg); } else { @@ -453,7 +281,7 @@ static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) static int generic_ide_probe(struct device *dev) { ide_drive_t *drive = to_ide_device(dev); - ide_driver_t *drv = to_ide_driver(dev->driver); + struct ide_driver *drv = to_ide_driver(dev->driver); return drv->probe ? drv->probe(drive) : -ENODEV; } @@ -461,7 +289,7 @@ static int generic_ide_probe(struct device *dev) static int generic_ide_remove(struct device *dev) { ide_drive_t *drive = to_ide_device(dev); - ide_driver_t *drv = to_ide_driver(dev->driver); + struct ide_driver *drv = to_ide_driver(dev->driver); if (drv->remove) drv->remove(drive); @@ -472,7 +300,7 @@ static int generic_ide_remove(struct device *dev) static void generic_ide_shutdown(struct device *dev) { ide_drive_t *drive = to_ide_device(dev); - ide_driver_t *drv = to_ide_driver(dev->driver); + struct ide_driver *drv = to_ide_driver(dev->driver); if (dev->driver && drv->shutdown) drv->shutdown(drive); @@ -660,6 +488,7 @@ MODULE_PARM_DESC(ignore_cable, "ignore cable detection"); void ide_port_apply_params(ide_hwif_t *hwif) { + ide_drive_t *drive; int i; if (ide_ignore_cable & (1 << hwif->index)) { @@ -668,8 +497,8 @@ void ide_port_apply_params(ide_hwif_t *hwif) hwif->cbl = ATA_CBL_PATA40_SHORT; } - for (i = 0; i < MAX_DRIVES; i++) - ide_dev_apply_params(&hwif->drives[i], i); + ide_port_for_each_dev(i, drive, hwif) + ide_dev_apply_params(drive, i); } /* diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c new file mode 100644 index 000000000000..e021078cd06b --- /dev/null +++ b/drivers/ide/it8172.c @@ -0,0 +1,166 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 IDE controller support + * + * Copyright (C) 2000 MontaVista Software Inc. + * Copyright (C) 2008 Shane McDonald + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "IT8172" + +static void it8172_set_pio_mode(ide_drive_t *drive, const u8 pio) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + u16 drive_enables; + u32 drive_timing; + + /* + * The highest value of DIOR/DIOW pulse width and recovery time + * that can be set in the IT8172 is 8 PCI clock cycles. As a result, + * it cannot be configured for PIO mode 0. This table sets these + * parameters to the maximum supported by the IT8172. + */ + static const u8 timings[] = { 0x3f, 0x3c, 0x1b, 0x12, 0x0a }; + + pci_read_config_word(dev, 0x40, &drive_enables); + pci_read_config_dword(dev, 0x44, &drive_timing); + + /* + * Enable port 0x44. The IT8172 spec is confused; it calls + * this register the "Slave IDE Timing Register", but in fact, + * it controls timing for both master and slave drives. + */ + drive_enables |= 0x4000; + + drive_enables &= drive->dn ? 0xc006 : 0xc060; + if (drive->media == ide_disk) + /* enable prefetch */ + drive_enables |= 0x0004 << (drive->dn * 4); + if (ata_id_has_iordy(drive->id)) + /* enable IORDY sample-point */ + drive_enables |= 0x0002 << (drive->dn * 4); + + drive_timing &= drive->dn ? 0x00003f00 : 0x000fc000; + drive_timing |= timings[pio] << (drive->dn * 6 + 8); + + pci_write_config_word(dev, 0x40, drive_enables); + pci_write_config_dword(dev, 0x44, drive_timing); +} + +static void it8172_set_dma_mode(ide_drive_t *drive, const u8 speed) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int u_speed = 0; + u8 reg48, reg4a; + + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x4a, ®4a); + + if (speed >= XFER_UDMA_0) { + u8 udma = speed - XFER_UDMA_0; + u_speed = udma << (drive->dn * 4); + + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + reg4a &= ~a_speed; + pci_write_config_byte(dev, 0x4a, reg4a | u_speed); + } else { + const u8 mwdma_to_pio[] = { 0, 3, 4 }; + u8 pio; + + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); + + pio = mwdma_to_pio[speed - XFER_MW_DMA_0]; + + it8172_set_pio_mode(drive, pio); + } +} + + +static const struct ide_port_ops it8172_port_ops = { + .set_pio_mode = it8172_set_pio_mode, + .set_dma_mode = it8172_set_dma_mode, +}; + +static const struct ide_port_info it8172_port_info __devinitdata = { + .name = DRV_NAME, + .port_ops = &it8172_port_ops, + .enablebits = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} }, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4 & ~ATA_PIO0, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, +}; + +static int __devinit it8172_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + return -ENODEV; /* IT8172 is more than an IDE controller */ + return ide_pci_init_one(dev, &it8172_port_info, NULL); +} + +static struct pci_device_id it8172_pci_tbl[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8172), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); + +static struct pci_driver it8172_pci_driver = { + .name = "IT8172_IDE", + .id_table = it8172_pci_tbl, + .probe = it8172_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init it8172_ide_init(void) +{ + return ide_pci_register_driver(&it8172_pci_driver); +} + +static void __exit it8172_ide_exit(void) +{ + pci_unregister_driver(&it8172_pci_driver); +} + +module_init(it8172_ide_init); +module_exit(it8172_ide_exit); + +MODULE_AUTHOR("Steve Longerbeam"); +MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c index 7c2feeb3c5ec..d7969b6d139e 100644 --- a/drivers/ide/it8213.c +++ b/drivers/ide/it8213.c @@ -25,7 +25,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int is_slave = drive->dn & 1; int master_port = 0x40; @@ -82,7 +82,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 maslave = 0x40; int a_speed = 3 << (drive->dn * 4); diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c index ef004089761b..0be27ac1f077 100644 --- a/drivers/ide/it821x.c +++ b/drivers/ide/it821x.c @@ -167,12 +167,10 @@ static void it821x_clock_strategy(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); - ide_drive_t *pair; + ide_drive_t *pair = ide_get_pair_dev(drive); int clock, altclock, sel = 0; u8 unit = drive->dn & 1, v; - pair = &hwif->drives[1 - unit]; - if(itdev->want[0][0] > itdev->want[1][0]) { clock = itdev->want[0][1]; altclock = itdev->want[1][1]; @@ -239,15 +237,13 @@ static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - ide_drive_t *pair; + ide_drive_t *pair = ide_get_pair_dev(drive); u8 unit = drive->dn & 1, set_pio = pio; /* Spec says 89 ref driver uses 88 */ static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; - pair = &hwif->drives[1 - unit]; - /* * Compute the best PIO mode we can for a given device. We must * pick a speed that does not cause problems with the other device @@ -279,7 +275,7 @@ static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) * the shared MWDMA/PIO timing register. */ -static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) +static void it821x_tune_mwdma(ide_drive_t *drive, u8 mode_wanted) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -316,7 +312,7 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) * controller when doing UDMA modes in pass through. */ -static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) +static void it821x_tune_udma(ide_drive_t *drive, u8 mode_wanted) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -516,6 +512,7 @@ static struct ide_dma_ops it821x_pass_through_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, + .dma_sff_read_status = ide_dma_sff_read_status, }; /** diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c index 13789060f407..83643ed9a426 100644 --- a/drivers/ide/ns87415.c +++ b/drivers/ide/ns87415.c @@ -56,7 +56,7 @@ static u8 superio_read_status(ide_hwif_t *hwif) return superio_ide_inb(hwif->io_ports.status_addr); } -static u8 superio_read_sff_dma_status(ide_hwif_t *hwif) +static u8 superio_dma_sff_read_status(ide_hwif_t *hwif) { return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS); } @@ -109,7 +109,6 @@ static const struct ide_tp_ops superio_tp_ops = { .exec_command = ide_exec_command, .read_status = superio_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = superio_read_sff_dma_status, .set_irq = ide_set_irq, @@ -132,18 +131,20 @@ static void __devinit superio_init_iops(struct hwif_s *hwif) tmp = superio_ide_inb(dma_stat); outb(tmp | 0x66, dma_stat); } +#else +#define superio_dma_sff_read_status ide_dma_sff_read_status #endif static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; /* * This routine either enables/disables (according to IDE_DFLAG_PRESENT) - * the IRQ associated with the port (HWIF(drive)), + * the IRQ associated with the port, * and selects either PIO or DMA handshaking for the next I/O operation. */ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; unsigned long flags; @@ -197,11 +198,11 @@ static void ns87415_selectproc (ide_drive_t *drive) static int ns87415_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u8 dma_stat = 0, dma_cmd = 0; drive->waiting_for_dma = 0; - dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); /* get DMA command mode */ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); /* stop DMA */ @@ -308,6 +309,7 @@ static const struct ide_dma_ops ns87415_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = superio_dma_sff_read_status, }; static const struct ide_port_info ns87415_chipset __devinitdata = { diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c index 122ed3c072fd..a7ac490c9ae3 100644 --- a/drivers/ide/palm_bk3710.c +++ b/drivers/ide/palm_bk3710.c @@ -324,8 +324,6 @@ static int __devinit palm_bk3710_init_dma(ide_hwif_t *hwif, hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET; - hwif->dma_ops = &sff_dma_ops; - return 0; } @@ -338,6 +336,7 @@ static const struct ide_port_ops palm_bk3710_ports_ops = { static struct ide_port_info __devinitdata palm_bk3710_port_info = { .init_dma = palm_bk3710_init_dma, .port_ops = &palm_bk3710_ports_ops, + .dma_ops = &sff_dma_ops, .host_flags = IDE_HFLAG_MMIO, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c index 211ae46e3e0c..f21290c4b447 100644 --- a/drivers/ide/pdc202xx_new.c +++ b/drivers/ide/pdc202xx_new.c @@ -143,7 +143,7 @@ static struct udma_timing { static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; @@ -219,7 +219,7 @@ static void pdcnew_reset(ide_drive_t *drive) * Deleted this because it is redundant from the caller. */ printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n", - HWIF(drive)->channel ? "Secondary" : "Primary"); + drive->hwif->channel ? "Secondary" : "Primary"); } /** diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c index 624e62e5cc9a..97193323aebf 100644 --- a/drivers/ide/pdc202xx_old.c +++ b/drivers/ide/pdc202xx_old.c @@ -39,7 +39,7 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *); static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 drive_pci = 0x60 + (drive->dn << 2); @@ -169,8 +169,8 @@ static void pdc202xx_dma_start(ide_drive_t *drive) if (drive->current_speed > XFER_UDMA_2) pdc_old_enable_66MHz_clock(drive->hwif); if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) { - struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; unsigned long high_16 = hwif->extra_base - 16; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u32 word_count = 0; @@ -189,7 +189,7 @@ static void pdc202xx_dma_start(ide_drive_t *drive) static int pdc202xx_dma_end(ide_drive_t *drive) { if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long high_16 = hwif->extra_base - 16; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u8 clock = 0; @@ -205,7 +205,7 @@ static int pdc202xx_dma_end(ide_drive_t *drive) static int pdc202xx_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long high_16 = hwif->extra_base - 16; u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); u8 sc1d = inb(high_16 + 0x001d); @@ -243,7 +243,7 @@ static void pdc202xx_reset_host (ide_hwif_t *hwif) static void pdc202xx_reset (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; ide_hwif_t *mate = hwif->mate; pdc202xx_reset_host(hwif); @@ -337,6 +337,7 @@ static const struct ide_dma_ops pdc20246_dma_ops = { .dma_test_irq = pdc202xx_dma_test_irq, .dma_lost_irq = pdc202xx_dma_lost_irq, .dma_timeout = pdc202xx_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_dma_ops pdc2026x_dma_ops = { @@ -348,6 +349,7 @@ static const struct ide_dma_ops pdc2026x_dma_ops = { .dma_test_irq = pdc202xx_dma_test_irq, .dma_lost_irq = pdc202xx_dma_lost_irq, .dma_timeout = pdc202xx_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; #define DECLARE_PDC2026X_DEV(udma, sectors) \ diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index 61d2d920a5cd..f1e2e4ef0d71 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -67,7 +67,7 @@ static int no_piix_dma; static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; @@ -136,7 +136,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 maslave = hwif->channel ? 0x42 : 0x40; int a_speed = 3 << (drive->dn * 4); @@ -224,7 +224,7 @@ static unsigned int init_chipset_ich(struct pci_dev *dev) */ static void ich_clear_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u8 dma_stat; /* @@ -260,6 +260,8 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ /* end marker */ { 0, } diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c index 7c481bb56fab..74625e821a43 100644 --- a/drivers/ide/pmac.c +++ b/drivers/ide/pmac.c @@ -955,7 +955,6 @@ static const struct ide_tp_ops pmac_tp_ops = { .exec_command = pmac_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = pmac_set_irq, @@ -1513,10 +1512,10 @@ use_pio_instead: static int pmac_ide_dma_setup(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent); - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = hwif->rq; u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4); if (!pmac_ide_build_dmatable(drive, rq)) { @@ -1637,7 +1636,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) break; if (++timeout > 100) { printk(KERN_WARNING "ide%d, ide_dma_test_irq \ - timeout flushing channel\n", HWIF(drive)->index); + timeout flushing channel\n", hwif->index); break; } } diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c index 4af4a8ce4cdf..9f9c0b3cc3a3 100644 --- a/drivers/ide/q40ide.c +++ b/drivers/ide/q40ide.c @@ -99,7 +99,6 @@ static const struct ide_tp_ops q40ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index bc27c7aba936..5b2e3af43c4b 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -202,7 +202,8 @@ static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio) recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120; } - qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time)); + qd_set_timing(drive, qd6500_compute_timing(drive->hwif, + active_time, recovery_time)); } static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio) @@ -245,11 +246,11 @@ static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio) printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio); } - if (!HWIF(drive)->channel && drive->media != ide_disk) { + if (!hwif->channel && drive->media != ide_disk) { outb(0x5f, QD_CONTROL_PORT); printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO " "and post-write buffer on %s.\n", - drive->name, HWIF(drive)->name); + drive->name, hwif->name); } qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time)); diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h index c83dea85e621..6636f9665d16 100644 --- a/drivers/ide/qd65xx.h +++ b/drivers/ide/qd65xx.h @@ -31,8 +31,8 @@ #define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) -#define QD_TIMING(drive) (byte)(((drive)->drive_data) & 0x00ff) -#define QD_TIMREG(drive) (byte)((((drive)->drive_data) & 0xff00) >> 8) +#define QD_TIMING(drive) (u8)(((drive)->drive_data) & 0x00ff) +#define QD_TIMREG(drive) (u8)((((drive)->drive_data) & 0xff00) >> 8) #define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) #define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c index ec7f766ef5e4..dbdd2985a0d8 100644 --- a/drivers/ide/sc1200.c +++ b/drivers/ide/sc1200.c @@ -125,7 +125,7 @@ out: static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned int reg, timings; unsigned short pci_clock; @@ -170,9 +170,9 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) */ static int sc1200_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long dma_base = hwif->dma_base; - byte dma_stat; + u8 dma_stat; dma_stat = inb(dma_base+2); /* get DMA status */ @@ -199,7 +199,7 @@ static int sc1200_dma_end(ide_drive_t *drive) static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; int mode = -1; /* @@ -292,6 +292,7 @@ static const struct ide_dma_ops sc1200_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_port_info sc1200_chipset __devinitdata = { diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c index 0f48f9dacfa5..8d2314b6327c 100644 --- a/drivers/ide/scc_pata.c +++ b/drivers/ide/scc_pata.c @@ -143,7 +143,7 @@ static u8 scc_read_altstatus(ide_hwif_t *hwif) return (u8)in_be32((void *)hwif->io_ports.ctl_addr); } -static u8 scc_read_sff_dma_status(ide_hwif_t *hwif) +static u8 scc_dma_sff_read_status(ide_hwif_t *hwif) { return (u8)in_be32((void *)(hwif->dma_base + 4)); } @@ -217,7 +217,7 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count) static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct scc_ports *ports = ide_get_hwifdata(hwif); unsigned long ctl_base = ports->ctl; unsigned long cckctrl_port = ctl_base + 0xff0; @@ -249,7 +249,7 @@ static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct scc_ports *ports = ide_get_hwifdata(hwif); unsigned long ctl_base = ports->ctl; unsigned long cckctrl_port = ctl_base + 0xff0; @@ -259,7 +259,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) unsigned long scrcst_port = ctl_base + 0x014; unsigned long udenvt_port = ctl_base + 0x018; unsigned long tdvhsel_port = ctl_base + 0x020; - int is_slave = (&hwif->drives[1] == drive); + int is_slave = drive->dn & 1; int offset, idx; unsigned long reg; unsigned long jcactsel; @@ -292,7 +292,7 @@ static void scc_dma_host_set(ide_drive_t *drive, int on) { ide_hwif_t *hwif = drive->hwif; u8 unit = drive->dn & 1; - u8 dma_stat = scc_ide_inb(hwif->dma_base + 4); + u8 dma_stat = scc_dma_sff_read_status(hwif); if (on) dma_stat |= (1 << (5 + unit)); @@ -316,7 +316,7 @@ static void scc_dma_host_set(ide_drive_t *drive, int on) static int scc_dma_setup(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = hwif->rq; unsigned int reading; u8 dma_stat; @@ -338,7 +338,7 @@ static int scc_dma_setup(ide_drive_t *drive) out_be32((void __iomem *)hwif->dma_base, reading); /* read DMA status for INTR & ERROR flags */ - dma_stat = in_be32((void __iomem *)(hwif->dma_base + 4)); + dma_stat = scc_dma_sff_read_status(hwif); /* clear INTR & ERROR flags */ out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6); @@ -367,7 +367,7 @@ static int __scc_dma_end(ide_drive_t *drive) /* stop DMA */ scc_ide_outb(dma_cmd & ~1, hwif->dma_base); /* get DMA status */ - dma_stat = scc_ide_inb(hwif->dma_base + 4); + dma_stat = scc_dma_sff_read_status(hwif); /* clear the INTR & ERROR bits */ scc_ide_outb(dma_stat | 6, hwif->dma_base + 4); /* purge DMA mappings */ @@ -387,7 +387,7 @@ static int __scc_dma_end(ide_drive_t *drive) static int scc_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; void __iomem *dma_base = (void __iomem *)hwif->dma_base; unsigned long intsts_port = hwif->dma_base + 0x014; u32 reg; @@ -405,17 +405,18 @@ static int scc_dma_end(ide_drive_t *drive) drive->name); data_loss = 1; if (retry++) { - struct request *rq = HWGROUP(drive)->rq; - int unit; + struct request *rq = hwif->rq; + ide_drive_t *drive; + int i; + /* ERROR_RESET and drive->crc_count are needed * to reduce DMA transfer mode in retry process. */ if (rq) rq->errors |= ERROR_RESET; - for (unit = 0; unit < MAX_DRIVES; unit++) { - ide_drive_t *drive = &hwif->drives[unit]; + + ide_port_for_each_dev(i, drive, hwif) drive->crc_count++; - } } } } @@ -496,7 +497,7 @@ static int scc_dma_end(ide_drive_t *drive) /* returns 1 if dma irq issued, 0 otherwise */ static int scc_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014); /* SCC errata A252,A308 workaround: Step4 */ @@ -852,7 +853,6 @@ static const struct ide_tp_ops scc_tp_ops = { .exec_command = scc_exec_command, .read_status = scc_read_status, .read_altstatus = scc_read_altstatus, - .read_sff_dma_status = scc_read_sff_dma_status, .set_irq = scc_set_irq, @@ -879,6 +879,7 @@ static const struct ide_dma_ops scc_dma_ops = { .dma_test_irq = scc_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = scc_dma_sff_read_status, }; #define DECLARE_SCC_DEV(name_str) \ diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c index 437bc919dafd..382102ba467b 100644 --- a/drivers/ide/serverworks.c +++ b/drivers/ide/serverworks.c @@ -151,7 +151,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed) static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 }; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 unit = drive->dn & 1; diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 9f1f9163a136..e85d1ed29c2a 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -130,7 +130,7 @@ int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d) * we tune the drive then try to grab DMA ownership if we want to be * the DMA end. This has to be become dynamic to handle hot-plug. */ - dma_stat = hwif->tp_ops->read_sff_dma_status(hwif); + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) { printk(KERN_INFO "%s %s: simplex device: DMA disabled\n", d->name, pci_name(dev)); @@ -377,6 +377,9 @@ int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d) hwif->dma_base = base; + if (hwif->dma_ops == NULL) + hwif->dma_ops = &sff_dma_ops; + if (ide_pci_check_simplex(hwif, d) < 0) return -1; @@ -393,8 +396,6 @@ int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d) if (ide_allocate_dma_engine(hwif)) return -1; - - hwif->dma_ops = &sff_dma_ops; } return 0; @@ -471,7 +472,7 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, */ for (port = 0; port < channels; ++port) { - const ide_pci_enablebit_t *e = &(d->enablebits[port]); + const struct ide_pci_enablebit *e = &d->enablebits[port]; if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) { @@ -519,8 +520,7 @@ static int do_ide_setup_pci_device(struct pci_dev *dev, if (ret < 0) goto out; - /* Is it an "IDE storage" device in non-PCI mode? */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5) { + if (ide_pci_is_in_compatibility_mode(dev)) { if (noisy) printk(KERN_INFO "%s %s: not 100%% native mode: will " "probe irqs later\n", d->name, pci_name(dev)); diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c index a687a7dfea6f..fdb9d7037694 100644 --- a/drivers/ide/sgiioc4.c +++ b/drivers/ide/sgiioc4.c @@ -123,7 +123,7 @@ static int sgiioc4_clearirq(ide_drive_t * drive) { u32 intr_reg; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2); @@ -181,7 +181,7 @@ sgiioc4_clearirq(ide_drive_t * drive) static void sgiioc4_dma_start(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4; unsigned int reg = readl((void __iomem *)ioc4_dma_addr); unsigned int temp_reg = reg | IOC4_S_DMA_START; @@ -209,7 +209,7 @@ sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) static int sgiioc4_dma_end(ide_drive_t *drive) { u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long dma_base = hwif->dma_base; int dma_stat = 0; unsigned long *ending_dma = ide_get_hwifdata(hwif); @@ -271,7 +271,7 @@ static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed) /* returns 1 if dma irq issued, 0 otherwise */ static int sgiioc4_dma_test_irq(ide_drive_t *drive) { - return sgiioc4_checkirq(HWIF(drive)); + return sgiioc4_checkirq(drive->hwif); } static void sgiioc4_dma_host_set(ide_drive_t *drive, int on) @@ -367,7 +367,7 @@ static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) { u32 ioc4_dma; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long dma_base = hwif->dma_base; unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 dma_addr, ending_dma_addr; @@ -427,7 +427,7 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) static unsigned int sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned int *table = hwif->dmatable_cpu; unsigned int count = 0, i = 1; struct scatterlist *sg; @@ -492,7 +492,7 @@ use_pio_instead: static int sgiioc4_dma_setup(ide_drive_t *drive) { - struct request *rq = HWGROUP(drive)->rq; + struct request *rq = drive->hwif->rq; unsigned int count = 0; int ddir; @@ -523,7 +523,6 @@ static const struct ide_tp_ops sgiioc4_tp_ops = { .exec_command = ide_exec_command, .read_status = sgiioc4_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c index 7d622d20bc4c..cb2b352b876b 100644 --- a/drivers/ide/siimage.c +++ b/drivers/ide/siimage.c @@ -114,7 +114,7 @@ static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long base = (unsigned long)hwif->hwif_data; u8 unit = drive->dn & 1; @@ -243,7 +243,7 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); ide_drive_t *pair = ide_get_pair_dev(drive); u32 speedt = 0; @@ -300,7 +300,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long base = (unsigned long)hwif->hwif_data; u16 ultra = 0, multi = 0; @@ -340,7 +340,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) /* returns 1 if dma irq issued, 0 otherwise */ static int siimage_io_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 dma_altstat = 0; unsigned long addr = siimage_selreg(hwif, 1); @@ -367,7 +367,7 @@ static int siimage_io_dma_test_irq(ide_drive_t *drive) static int siimage_mmio_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long addr = siimage_selreg(hwif, 0x1); void __iomem *sata_error_addr = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; @@ -717,6 +717,7 @@ static const struct ide_dma_ops sil_dma_ops = { .dma_test_irq = siimage_dma_test_irq, .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, + .dma_sff_read_status = ide_dma_sff_read_status, }; #define DECLARE_SII_DEV(p_ops) \ diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index ad32e18c5ba3..9ec1a4a4432c 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -274,7 +274,7 @@ static void sis_program_timings(ide_drive_t *drive, const u8 mode) static void config_drive_art_rwp(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 reg4bh = 0; u8 rw_prefetch = 0; diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c index 84dc33602ff8..48cc748c5043 100644 --- a/drivers/ide/sl82c105.c +++ b/drivers/ide/sl82c105.c @@ -140,7 +140,7 @@ static inline void sl82c105_reset_host(struct pci_dev *dev) */ static void sl82c105_dma_lost_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; u8 dma_cmd; @@ -177,7 +177,7 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive) */ static void sl82c105_dma_start(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int reg = 0x44 + drive->dn * 4; @@ -299,6 +299,7 @@ static const struct ide_dma_ops sl82c105_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = sl82c105_dma_lost_irq, .dma_timeout = sl82c105_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_port_info sl82c105_chipset __devinitdata = { diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c index 0f759e4ed779..40b4b94a4288 100644 --- a/drivers/ide/slc90e66.c +++ b/drivers/ide/slc90e66.c @@ -20,7 +20,7 @@ static DEFINE_SPINLOCK(slc90e66_lock); static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; @@ -73,7 +73,7 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 maslave = hwif->channel ? 0x42 : 0x40; int sitre = 0, a_speed = 7 << (drive->dn * 4); diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c index 93e2cce4b296..84109f5a1632 100644 --- a/drivers/ide/tc86c001.c +++ b/drivers/ide/tc86c001.c @@ -15,7 +15,7 @@ static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); u16 mode, scr = inw(scr_port); @@ -62,13 +62,12 @@ static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio) */ static int tc86c001_timer_expiry(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; ide_expiry_t *expiry = ide_get_hwifdata(hwif); - ide_hwgroup_t *hwgroup = HWGROUP(drive); u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); /* Restore a higher level driver's expiry handler first. */ - hwgroup->expiry = expiry; + hwif->expiry = expiry; if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */ unsigned long sc_base = hwif->config_data; @@ -110,11 +109,10 @@ static int tc86c001_timer_expiry(ide_drive_t *drive) static void tc86c001_dma_start(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - ide_hwgroup_t *hwgroup = HWGROUP(drive); + ide_hwif_t *hwif = drive->hwif; unsigned long sc_base = hwif->config_data; unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); - unsigned long nsectors = hwgroup->rq->nr_sectors; + unsigned long nsectors = hwif->rq->nr_sectors; /* * We have to manually load the sector count and size into @@ -125,8 +123,8 @@ static void tc86c001_dma_start(ide_drive_t *drive) outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ /* Install our timeout expiry hook, saving the current handler... */ - ide_set_hwifdata(hwif, hwgroup->expiry); - hwgroup->expiry = &tc86c001_timer_expiry; + ide_set_hwifdata(hwif, hwif->expiry); + hwif->expiry = &tc86c001_timer_expiry; ide_dma_start(drive); } @@ -190,6 +188,7 @@ static const struct ide_dma_ops tc86c001_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, }; static const struct ide_port_info tc86c001_chipset __devinitdata = { diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c index b6ff40336aa9..8773c3ba7462 100644 --- a/drivers/ide/triflex.c +++ b/drivers/ide/triflex.c @@ -36,7 +36,7 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u32 triflex_timings = 0; u16 timing = 0; diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c index 2a5ea90cf8b8..b6a1285a4021 100644 --- a/drivers/ide/trm290.c +++ b/drivers/ide/trm290.c @@ -144,7 +144,7 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u16 reg = 0; unsigned long flags; @@ -184,7 +184,7 @@ static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command) static int trm290_dma_setup(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; unsigned int count, rw; if (rq_data_dir(rq)) { @@ -222,15 +222,15 @@ static int trm290_dma_end(ide_drive_t *drive) drive->waiting_for_dma = 0; /* purge DMA mappings */ ide_destroy_dmatable(drive); - status = inw(HWIF(drive)->dma_base + 2); + status = inw(drive->hwif->dma_base + 2); + return status != 0x00ff; } static int trm290_dma_test_irq(ide_drive_t *drive) { - u16 status; + u16 status = inw(drive->hwif->dma_base + 2); - status = inw(HWIF(drive)->dma_base + 2); return status == 0x00ff; } diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index 4a8c5a21bd4c..882f6f07c476 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -293,7 +293,7 @@ static int tx4939ide_dma_setup(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; void __iomem *base = TX4939IDE_BASE(hwif); - struct request *rq = hwif->hwgroup->rq; + struct request *rq = hwif->rq; u8 reading; int nent; @@ -397,6 +397,17 @@ static int tx4939ide_dma_test_irq(ide_drive_t *drive) return found; } +#ifdef __BIG_ENDIAN +static u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif) +{ + void __iomem *base = TX4939IDE_BASE(hwif); + + return tx4939ide_readb(base, TX4939IDE_DMA_Stat); +} +#else +#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status +#endif + static void tx4939ide_init_hwif(ide_hwif_t *hwif) { void __iomem *base = TX4939IDE_BASE(hwif); @@ -443,13 +454,6 @@ static void tx4939ide_tf_load_fixup(ide_drive_t *drive, ide_task_t *task) #ifdef __BIG_ENDIAN -static u8 tx4939ide_read_sff_dma_status(ide_hwif_t *hwif) -{ - void __iomem *base = TX4939IDE_BASE(hwif); - - return tx4939ide_readb(base, TX4939IDE_DMA_Stat); -} - /* custom iops (independent from SWAP_IO_SPACE) */ static u8 tx4939ide_inb(unsigned long port) { @@ -585,7 +589,6 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = tx4939ide_read_sff_dma_status, .set_irq = ide_set_irq, @@ -609,7 +612,6 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, .set_irq = ide_set_irq, @@ -638,6 +640,7 @@ static const struct ide_dma_ops tx4939ide_dma_ops = { .dma_test_irq = tx4939ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timeout = ide_dma_timeout, + .dma_sff_read_status = tx4939ide_dma_sff_read_status, }; static const struct ide_port_info tx4939ide_port_info __initdata = { diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c index e29978cf6197..0608d41fb6d0 100644 --- a/drivers/ide/umc8672.c +++ b/drivers/ide/umc8672.c @@ -106,22 +106,21 @@ static void umc_set_speeds(u8 speeds[]) static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = drive->hwif; - ide_hwgroup_t *mate_hwgroup = hwif->mate ? hwif->mate->hwgroup : NULL; + ide_hwif_t *hwif = drive->hwif, *mate = hwif->mate; unsigned long uninitialized_var(flags); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); - if (mate_hwgroup) - spin_lock_irqsave(&mate_hwgroup->lock, flags); - if (mate_hwgroup && mate_hwgroup->handler) { + if (mate) + spin_lock_irqsave(&mate->lock, flags); + if (mate && mate->handler) { printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n"); } else { current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; umc_set_speeds(current_speeds); } - if (mate_hwgroup) - spin_unlock_irqrestore(&mate_hwgroup->lock, flags); + if (mate) + spin_unlock_irqrestore(&mate->lock, flags); } static const struct ide_port_ops umc8672_port_ops = { diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index 2a812d3207e9..fecc0e03c3fc 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -178,7 +178,7 @@ static void via_set_drive(ide_drive_t *drive, const u8 speed) ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); } - via_set_speed(HWIF(drive), drive->dn, &t); + via_set_speed(hwif, drive->dn, &t); } /** diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 22bf981d393b..82607add69a9 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -554,7 +554,7 @@ thermostat_init(void) const u32 *prop; int i = 0, offset = 0; int err; - + np = of_find_node_by_name(NULL, "fan"); if (!np) return -ENODEV; @@ -613,13 +613,13 @@ thermostat_init(void) } of_dev = of_platform_device_create(np, "temperatures", NULL); - + of_node_put(np); + if (of_dev == NULL) { printk(KERN_ERR "Can't register temperatures device !\n"); - of_node_put(np); return -ENODEV; } - + err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature); err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature); err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit); diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 65d69665f1fc..6a32680dbb1b 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -79,6 +79,10 @@ static int dvb_device_open(struct inode *inode, struct file *file) file->private_data = dvbdev; old_fops = file->f_op; file->f_op = fops_get(dvbdev->fops); + if (file->f_op == NULL) { + file->f_op = old_fops; + goto fail; + } if(file->f_op->open) err = file->f_op->open(inode,file); if (err) { @@ -90,6 +94,7 @@ static int dvb_device_open(struct inode *inode, struct file *file) unlock_kernel(); return err; } +fail: up_read(&minor_rwsem); unlock_kernel(); return -ENODEV; diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index d450cab20be4..b617bf05e2d7 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -203,7 +203,6 @@ static int poll_one(struct file *file, struct poll_wqueues *pwq) table = &pwq->pt; for (;;) { int mask; - set_current_state(TASK_INTERRUPTIBLE); mask = file->f_op->poll(file, table); if (mask & POLLIN) break; @@ -212,9 +211,8 @@ static int poll_one(struct file *file, struct poll_wqueues *pwq) retval = -ERESTARTSYS; break; } - schedule(); + poll_schedule(pwq, TASK_INTERRUPTIBLE); } - set_current_state(TASK_RUNNING); poll_freewait(pwq); return retval; } diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index a7dd03e8d332..0ee4264f5db7 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -52,7 +52,6 @@ static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, /** * i2o_device_claim - claim a device for use by an OSM * @dev: I2O device to claim - * @drv: I2O driver which wants to claim the device * * Do the leg work to assign a device to a given OSM. If the claim succeeds, * the owner is the primary. If the attempt fails a negative errno code @@ -80,7 +79,6 @@ int i2o_device_claim(struct i2o_device *dev) /** * i2o_device_claim_release - release a device that the OSM is using * @dev: device to release - * @drv: driver which claimed the device * * Drop a claim by an OSM on a given I2O device. * diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index e0d474b17433..a0421efe04ca 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -173,7 +173,6 @@ void i2o_driver_unregister(struct i2o_driver *drv) * i2o_driver_dispatch - dispatch an I2O reply message * @c: I2O controller of the message * @m: I2O message number - * @msg: I2O message to be delivered * * The reply is delivered to the driver from which the original message * was. This function is only called from interrupt context. diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index b5f6add34b0b..dc14b0b9cbfa 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -104,8 +104,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi } sp->irq = pdev->irq; - sp->base_address = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + sp->base_address = pci_ioremap_bar(pdev, 0); if (!sp->base_address) { dev_err(sp->dev, "Failed to ioremap pci memory\n"); result = -ENODEV; diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 6f76573e7c8a..60b0b1a4fb3a 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -269,6 +269,16 @@ ioc4_variant(struct ioc4_driver_data *idd) return IOC4_VARIANT_PCI_RT; } +static void +ioc4_load_modules(struct work_struct *work) +{ + /* arg just has to be freed */ + + request_module("sgiioc4"); + + kfree(work); +} + /* Adds a new instance of an IOC4 card */ static int ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) @@ -378,6 +388,30 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) } mutex_unlock(&ioc4_mutex); + /* Request sgiioc4 IDE driver on boards that bring that functionality + * off of IOC4. The root filesystem may be hosted on a drive connected + * to IOC4, so we need to make sure the sgiioc4 driver is loaded as it + * won't be picked up by modprobes due to the ioc4 module owning the + * PCI device. + */ + if (idd->idd_variant != IOC4_VARIANT_PCI_RT) { + struct work_struct *work; + work = kzalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!work) { + printk(KERN_WARNING + "%s: IOC4 unable to allocate memory for " + "load of sub-modules.\n", __func__); + } else { + /* Request the module from a work procedure as the + * modprobe goes out to a userland helper and that + * will hang if done directly from ioc4_probe(). + */ + printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n"); + INIT_WORK(work, ioc4_load_modules); + schedule_work(work); + } + } + return 0; out_misc_region: @@ -462,6 +496,8 @@ ioc4_init(void) static void __devexit ioc4_exit(void) { + /* Ensure ioc4_load_modules() has completed before exiting */ + flush_scheduled_work(); pci_unregister_driver(&ioc4_driver); } diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index e71eba31decb..be5672a98702 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -354,8 +354,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, fm->has_ms_pif = tifm_7xx1_has_ms_pif; pci_set_drvdata(dev, fm); - fm->addr = ioremap(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + fm->addr = pci_ioremap_bar(dev, 0); if (!fm->addr) goto err_out_free; diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index ac2a805ac7ea..8901ecf6e037 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -84,7 +84,7 @@ int parport_wait_event (struct parport *port, signed long timeout) add_timer (&timer); ret = down_interruptible (&port->physport->ieee1284.irq); - if (!del_timer (&timer) && !ret) + if (!del_timer_sync(&timer) && !ret) /* Timed out. */ ret = 1; diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c index 956d3e79f6aa..addb87cf44d9 100644 --- a/drivers/rapidio/rio-driver.c +++ b/drivers/rapidio/rio-driver.c @@ -79,7 +79,6 @@ void rio_dev_put(struct rio_dev *rdev) /** * rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure - * @id: the RIO device id structure to match against * @dev: the RIO device structure to match against * * return 0 and set rio_dev->driver when drv claims rio_dev, else error diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 165a81843357..4ad831de41ad 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -35,8 +35,8 @@ config RTC_HCTOSYS_DEVICE default "rtc0" help The RTC device that will be used to (re)initialize the system - clock, usually rtc0. Initialization is done when the system - starts up, and when it resumes from a low power state. This + clock, usually rtc0. Initialization is done when the system + starts up, and when it resumes from a low power state. This device should record time in UTC, since the kernel won't do timezone correction. @@ -44,7 +44,7 @@ config RTC_HCTOSYS_DEVICE functions run, so it must usually be statically linked. This clock should be battery-backed, so that it reads the correct - time when the system boots from a power-off state. Otherwise, your + time when the system boots from a power-off state. Otherwise, your system will need an external clock source (like an NTP server). If the clock you specify here is not battery backed, it may still @@ -69,8 +69,7 @@ config RTC_INTF_SYSFS Say yes here if you want to use your RTCs using sysfs interfaces, /sys/class/rtc/rtc0 through /sys/.../rtcN. - This driver can also be built as a module. If so, the module - will be called rtc-sysfs. + If unsure, say Y. config RTC_INTF_PROC boolean "/proc/driver/rtc (procfs for rtc0)" @@ -78,11 +77,10 @@ config RTC_INTF_PROC default RTC_CLASS help Say yes here if you want to use your first RTC through the proc - interface, /proc/driver/rtc. Other RTCs will not be available + interface, /proc/driver/rtc. Other RTCs will not be available through that API. - This driver can also be built as a module. If so, the module - will be called rtc-proc. + If unsure, say Y. config RTC_INTF_DEV boolean "/dev/rtcN (character devices)" @@ -90,12 +88,14 @@ config RTC_INTF_DEV help Say yes here if you want to use your RTCs using the /dev interfaces, which "udev" sets up as /dev/rtc0 through - /dev/rtcN. You may want to set up a symbolic link so one - of these can be accessed as /dev/rtc, which is a name - expected by "hwclock" and some other programs. + /dev/rtcN. - This driver can also be built as a module. If so, the module - will be called rtc-dev. + You may want to set up a symbolic link so one of these + can be accessed as /dev/rtc, which is a name + expected by "hwclock" and some other programs. Recent + versions of "udev" are known to set up the symlink for you. + + If unsure, say Y. config RTC_INTF_DEV_UIE_EMUL bool "RTC UIE emulation on dev interface" @@ -132,14 +132,14 @@ config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" help If you say yes here you get support for various compatible RTC - chips (often with battery backup) connected with I2C. This driver + chips (often with battery backup) connected with I2C. This driver should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, - and probably other chips. In some cases the RTC must already + and probably other chips. In some cases the RTC must already have been initialized (by manufacturing or a bootloader). The first seven registers on these chips hold an RTC, and other registers may add features such as NVRAM, a trickle charger for - the RTC/NVRAM backup power, and alarms. NVRAM is visible in + the RTC/NVRAM backup power, and alarms. NVRAM is visible in sysfs, but other chip features may not be available. This driver can also be built as a module. If so, the module @@ -150,10 +150,10 @@ config RTC_DRV_DS1374 depends on RTC_CLASS && I2C help If you say yes here you get support for Dallas Semiconductor - DS1374 real-time clock chips. If an interrupt is associated + DS1374 real-time clock chips. If an interrupt is associated with the device, the alarm functionality is supported. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called rtc-ds1374. config RTC_DRV_DS1672 @@ -247,7 +247,7 @@ config RTC_DRV_TWL92330 help If you say yes here you get support for the RTC on the TWL92330 "Menelaus" power management chip, used with OMAP2 - platforms. The support is integrated with the rest of + platforms. The support is integrated with the rest of the Menelaus driver; it's not separate module. config RTC_DRV_TWL4030 @@ -308,7 +308,7 @@ config RTC_DRV_DS1305 tristate "Dallas/Maxim DS1305/DS1306" help Select this driver to get support for the Dallas/Maxim DS1305 - and DS1306 real time clock chips. These support a trickle + and DS1306 real time clock chips. These support a trickle charger, alarms, and NVRAM in addition to the clock. This driver can also be built as a module. If so, the module @@ -317,7 +317,8 @@ config RTC_DRV_DS1305 config RTC_DRV_DS1390 tristate "Dallas/Maxim DS1390/93/94" help - If you say yes here you get support for the DS1390/93/94 chips. + If you say yes here you get support for the + Dallas/Maxim DS1390/93/94 chips. This driver only supports the RTC feature, and not other chip features such as alarms and trickle charging. @@ -381,7 +382,7 @@ config RTC_DRV_CMOS or LPC bus chips, and so on. Your system will need to define the platform device used by - this driver, otherwise it won't be accessible. This means + this driver, otherwise it won't be accessible. This means you can safely enable this driver if you don't know whether or not your board has this kind of hardware. @@ -598,7 +599,7 @@ config RTC_DRV_AT91RM9200 depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL help Driver for the internal RTC (Realtime Clock) module found on - Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips + Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips this is powered by the backup power supply. config RTC_DRV_AT91SAM9 @@ -620,8 +621,8 @@ config RTC_DRV_AT91SAM9_RTT prompt "RTT module Number" if ARCH_AT91SAM9263 depends on RTC_DRV_AT91SAM9 help - More than one RTT module is available. You can choose which - one will be used as an RTC. The default of zero is normally + More than one RTT module is available. You can choose which + one will be used as an RTC. The default of zero is normally OK to use, though some systems use that for non-RTC purposes. config RTC_DRV_AT91SAM9_GPBR @@ -633,10 +634,20 @@ config RTC_DRV_AT91SAM9_GPBR depends on RTC_DRV_AT91SAM9 help The RTC driver needs to use one of the General Purpose Backup - Registers (GPBRs) as well as the RTT. You can choose which one - will be used. The default of zero is normally OK to use, but + Registers (GPBRs) as well as the RTT. You can choose which one + will be used. The default of zero is normally OK to use, but on some systems other software needs to use that register. +config RTC_DRV_AU1XXX + tristate "Au1xxx Counter0 RTC support" + depends on SOC_AU1X00 + help + This is a driver for the Au1xxx on-chip Counter0 (Time-Of-Year + counter) to be used as a RTC. + + This driver can also be built as a module. If so, the module + will be called rtc-au1xxx. + config RTC_DRV_BFIN tristate "Blackfin On-Chip RTC" depends on BLACKFIN && !BF561 @@ -669,6 +680,17 @@ config RTC_DRV_PPC the RTC. This exposes that functionality through the generic RTC class. +config RTC_DRV_PXA + tristate "PXA27x/PXA3xx" + depends on ARCH_PXA + help + If you say Y here you will get access to the real time clock + built into your PXA27x or PXA3xx CPU. + + This RTC driver uses PXA RTC registers available since pxa27x + series (RDxR, RYxR) instead of legacy RCNR, RTAR. + + config RTC_DRV_SUN4V bool "SUN4V Hypervisor RTC" depends on SPARC64 @@ -683,4 +705,22 @@ config RTC_DRV_STARFIRE If you say Y here you will get support for the RTC found on Starfire systems. +config RTC_DRV_TX4939 + tristate "TX4939 SoC" + depends on SOC_TX4939 + help + Driver for the internal RTC (Realtime Clock) module found on + Toshiba TX4939 SoC. + +config RTC_DRV_MV + tristate "Marvell SoC RTC" + depends on ARCH_KIRKWOOD + help + If you say yes here you will get support for the in-chip RTC + that can be found in some of Marvell's SoC devices, such as + the Kirkwood 88F6281 and 88F6192. + + This driver can also be built as a module. If so, the module + will be called rtc-mv. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6e79c912bf9e..9a4340d48f26 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -20,6 +20,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o +obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o @@ -47,6 +48,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o +obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o @@ -54,6 +56,7 @@ obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o +obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o @@ -66,6 +69,7 @@ obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o +obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 4dfdf019fccc..be5a6b73e601 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -48,9 +48,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) struct rtc_time tm; struct timespec ts = current_kernel_time(); - if (strncmp(rtc->dev.bus_id, - CONFIG_RTC_HCTOSYS_DEVICE, - BUS_ID_SIZE) != 0) + if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); @@ -71,20 +69,18 @@ static int rtc_resume(struct device *dev) time_t newtime; struct timespec time; - if (strncmp(rtc->dev.bus_id, - CONFIG_RTC_HCTOSYS_DEVICE, - BUS_ID_SIZE) != 0) + if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { - pr_debug("%s: bogus resume time\n", rtc->dev.bus_id); + pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); return 0; } rtc_tm_to_time(&tm, &newtime); if (newtime <= oldtime) { if (newtime < oldtime) - pr_debug("%s: time travel!\n", rtc->dev.bus_id); + pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } @@ -156,7 +152,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, init_waitqueue_head(&rtc->irq_queue); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); - snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); + dev_set_name(&rtc->dev, "rtc%d", id); rtc_dev_prepare(rtc); @@ -169,7 +165,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc_proc_add_device(rtc); dev_info(dev, "rtc core: registered %s as %s\n", - rtc->name, rtc->dev.bus_id); + rtc->name, dev_name(&rtc->dev)); return rtc; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index fd2c652504ff..4348c4b0d453 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -50,10 +50,15 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) if (!rtc->ops) err = -ENODEV; - else if (!rtc->ops->set_time) - err = -EINVAL; - else + else if (rtc->ops->set_time) err = rtc->ops->set_time(rtc->dev.parent, tm); + else if (rtc->ops->set_mmss) { + unsigned long secs; + err = rtc_tm_to_time(tm, &secs); + if (err == 0) + err = rtc->ops->set_mmss(rtc->dev.parent, secs); + } else + err = -EINVAL; mutex_unlock(&rtc->ops_lock); return err; @@ -389,7 +394,7 @@ static int __rtc_match(struct device *dev, void *data) { char *name = (char *)data; - if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) + if (strcmp(dev_name(dev), name) == 0) return 1; return 0; } @@ -504,9 +509,6 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) if (rtc->ops->irq_set_freq == NULL) return -ENXIO; - if (!is_power_of_2(freq)) - return -EINVAL; - spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index 90b9a6503e15..e1ec33e40e38 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -205,7 +205,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) { struct resource *regs; struct rtc_at32ap700x *rtc; - int irq = -1; + int irq; int ret; rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL); @@ -222,7 +222,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { + if (irq <= 0) { dev_dbg(&pdev->dev, "could not get irq\n"); ret = -ENXIO; goto out; diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c new file mode 100644 index 000000000000..8906a688e6a6 --- /dev/null +++ b/drivers/rtc/rtc-au1xxx.c @@ -0,0 +1,153 @@ +/* + * Au1xxx counter0 (aka Time-Of-Year counter) RTC interface driver. + * + * Copyright (C) 2008 Manuel Lauss <mano@roarinelk.homelinux.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +/* All current Au1xxx SoCs have 2 counters fed by an external 32.768 kHz + * crystal. Counter 0, which keeps counting during sleep/powerdown, is + * used to count seconds since the beginning of the unix epoch. + * + * The counters must be configured and enabled by bootloader/board code; + * no checks as to whether they really get a proper 32.768kHz clock are + * made as this would take far too long. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/rtc.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <asm/mach-au1x00/au1000.h> + +/* 32kHz clock enabled and detected */ +#define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S) + +static int au1xtoy_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long t; + + t = au_readl(SYS_TOYREAD); + + rtc_time_to_tm(t, tm); + + return rtc_valid_tm(tm); +} + +static int au1xtoy_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long t; + + rtc_tm_to_time(tm, &t); + + au_writel(t, SYS_TOYWRITE); + au_sync(); + + /* wait for the pending register write to succeed. This can + * take up to 6 seconds... + */ + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S) + msleep(1); + + return 0; +} + +static struct rtc_class_ops au1xtoy_rtc_ops = { + .read_time = au1xtoy_rtc_read_time, + .set_time = au1xtoy_rtc_set_time, +}; + +static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtcdev; + unsigned long t; + int ret; + + t = au_readl(SYS_COUNTER_CNTRL); + if (!(t & CNTR_OK)) { + dev_err(&pdev->dev, "counters not working; aborting.\n"); + ret = -ENODEV; + goto out_err; + } + + ret = -ETIMEDOUT; + + /* set counter0 tickrate to 1Hz if necessary */ + if (au_readl(SYS_TOYTRIM) != 32767) { + /* wait until hardware gives access to TRIM register */ + t = 0x00100000; + while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S) && t--) + msleep(1); + + if (!t) { + /* timed out waiting for register access; assume + * counters are unusable. + */ + dev_err(&pdev->dev, "timeout waiting for access\n"); + goto out_err; + } + + /* set 1Hz TOY tick rate */ + au_writel(32767, SYS_TOYTRIM); + au_sync(); + } + + /* wait until the hardware allows writes to the counter reg */ + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S) + msleep(1); + + rtcdev = rtc_device_register("rtc-au1xxx", &pdev->dev, + &au1xtoy_rtc_ops, THIS_MODULE); + if (IS_ERR(rtcdev)) { + ret = PTR_ERR(rtcdev); + goto out_err; + } + + platform_set_drvdata(pdev, rtcdev); + + return 0; + +out_err: + return ret; +} + +static int __devexit au1xtoy_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtcdev = platform_get_drvdata(pdev); + + rtc_device_unregister(rtcdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver au1xrtc_driver = { + .driver = { + .name = "rtc-au1xxx", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(au1xtoy_rtc_remove), +}; + +static int __init au1xtoy_rtc_init(void) +{ + return platform_driver_probe(&au1xrtc_driver, au1xtoy_rtc_probe); +} + +static void __exit au1xtoy_rtc_exit(void) +{ + platform_driver_unregister(&au1xrtc_driver); +} + +module_init(au1xtoy_rtc_init); +module_exit(au1xtoy_rtc_exit); + +MODULE_DESCRIPTION("Au1xxx TOY-counter-based RTC driver"); +MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtc-au1xxx"); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 34439ce3967e..aafd3e6ebb0d 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -390,7 +390,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) /* Register our RTC with the RTC framework */ rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc))) { + if (unlikely(IS_ERR(rtc->rtc_dev))) { ret = PTR_ERR(rtc->rtc_dev); goto err_irq; } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 6cf8e282338f..b6d35f50e404 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mod_devicetable.h> +#include <linux/log2.h> /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> @@ -58,7 +59,7 @@ struct cmos_rtc { }; /* both platform and pnp busses use negative numbers for invalid irqs */ -#define is_valid_irq(n) ((n) >= 0) +#define is_valid_irq(n) ((n) > 0) static const char driver_name[] = "rtc_cmos"; @@ -384,6 +385,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq) if (!is_valid_irq(cmos->irq)) return -ENXIO; + if (!is_power_of_2(freq)) + return -EINVAL; /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */ f = ffs(freq); if (f-- > 16) @@ -729,7 +732,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) cmos_rtc.dev = dev; dev_set_drvdata(dev, &cmos_rtc); - rename_region(ports, cmos_rtc.rtc->dev.bus_id); + rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); @@ -777,7 +780,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = cmos_interrupt; retval = request_irq(rtc_irq, rtc_cmos_int_handler, - IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id, + IRQF_DISABLED, dev_name(&cmos_rtc.rtc->dev), cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); @@ -795,7 +798,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) } pr_info("%s: alarms up to one %s%s, %zd bytes nvram%s\n", - cmos_rtc.rtc->dev.bus_id, + dev_name(&cmos_rtc.rtc->dev), is_valid_irq(rtc_irq) ? (cmos_rtc.mon_alrm ? "year" @@ -885,7 +888,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) } pr_debug("%s: suspend%s, ctrl %02x\n", - cmos_rtc.rtc->dev.bus_id, + dev_name(&cmos_rtc.rtc->dev), (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); @@ -941,7 +944,7 @@ static int cmos_resume(struct device *dev) } pr_debug("%s: resume, ctrl %02x\n", - cmos_rtc.rtc->dev.bus_id, + dev_name(&cmos_rtc.rtc->dev), tmp); return 0; diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c index 9a234a4ec06d..4aedc705518c 100644 --- a/drivers/rtc/rtc-ds1216.c +++ b/drivers/rtc/rtc-ds1216.c @@ -10,7 +10,7 @@ #include <linux/platform_device.h> #include <linux/bcd.h> -#define DRV_VERSION "0.1" +#define DRV_VERSION "0.2" struct ds1216_regs { u8 tsec; @@ -101,7 +101,8 @@ static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_year = bcd2bin(regs.year); if (tm->tm_year < 70) tm->tm_year += 100; - return 0; + + return rtc_valid_tm(tm); } static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -138,9 +139,8 @@ static const struct rtc_class_ops ds1216_rtc_ops = { .set_time = ds1216_rtc_set_time, }; -static int __devinit ds1216_rtc_probe(struct platform_device *pdev) +static int __init ds1216_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; struct resource *res; struct ds1216_priv *priv; int ret = 0; @@ -152,7 +152,10 @@ static int __devinit ds1216_rtc_probe(struct platform_device *pdev) priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) return -ENOMEM; - priv->size = res->end - res->start + 1; + + platform_set_drvdata(pdev, priv); + + priv->size = resource_size(res); if (!request_mem_region(res->start, priv->size, pdev->name)) { ret = -EBUSY; goto out; @@ -163,22 +166,18 @@ static int __devinit ds1216_rtc_probe(struct platform_device *pdev) ret = -ENOMEM; goto out; } - rtc = rtc_device_register("ds1216", &pdev->dev, + priv->rtc = rtc_device_register("ds1216", &pdev->dev, &ds1216_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); goto out; } - priv->rtc = rtc; - platform_set_drvdata(pdev, priv); /* dummy read to get clock into a known state */ ds1216_read(priv->ioaddr, dummy); return 0; out: - if (priv->rtc) - rtc_device_unregister(priv->rtc); if (priv->ioaddr) iounmap(priv->ioaddr); if (priv->baseaddr) @@ -187,7 +186,7 @@ out: return ret; } -static int __devexit ds1216_rtc_remove(struct platform_device *pdev) +static int __exit ds1216_rtc_remove(struct platform_device *pdev) { struct ds1216_priv *priv = platform_get_drvdata(pdev); @@ -203,13 +202,12 @@ static struct platform_driver ds1216_rtc_platform_driver = { .name = "rtc-ds1216", .owner = THIS_MODULE, }, - .probe = ds1216_rtc_probe, - .remove = __devexit_p(ds1216_rtc_remove), + .remove = __exit_p(ds1216_rtc_remove), }; static int __init ds1216_rtc_init(void) { - return platform_driver_register(&ds1216_rtc_platform_driver); + return platform_driver_probe(&ds1216_rtc_platform_driver, ds1216_rtc_probe); } static void __exit ds1216_rtc_exit(void) diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 599e976bf014..e54b5c619bdf 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -1,5 +1,5 @@ /* - * rtc-ds1390.c -- driver for DS1390/93/94 + * rtc-ds1390.c -- driver for the Dallas/Maxim DS1390/93/94 SPI RTC * * Copyright (C) 2008 Mercury IMC Ltd * Written by Mark Jackson <mpfj@mimc.co.uk> @@ -8,11 +8,13 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * NOTE : Currently this driver only supports the bare minimum for read - * and write the RTC. The extra features provided by the chip family + * NOTE: Currently this driver only supports the bare minimum for read + * and write the RTC. The extra features provided by the chip family * (alarms, trickle charger, different control registers) are unavailable. */ +#include <linux/init.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/spi/spi.h> @@ -42,20 +44,6 @@ struct ds1390 { u8 txrx_buf[9]; /* cmd + 8 registers */ }; -static void ds1390_set_reg(struct device *dev, unsigned char address, - unsigned char data) -{ - struct spi_device *spi = to_spi_device(dev); - struct ds1390 *chip = dev_get_drvdata(dev); - - /* Set MSB to indicate write */ - chip->txrx_buf[0] = address | 0x80; - chip->txrx_buf[1] = data; - - /* do the i/o */ - spi_write_then_read(spi, chip->txrx_buf, 2, NULL, 0); -} - static int ds1390_get_reg(struct device *dev, unsigned char address, unsigned char *data) { @@ -78,7 +66,7 @@ static int ds1390_get_reg(struct device *dev, unsigned char address, return 0; } -static int ds1390_get_datetime(struct device *dev, struct rtc_time *dt) +static int ds1390_read_time(struct device *dev, struct rtc_time *dt) { struct spi_device *spi = to_spi_device(dev); struct ds1390 *chip = dev_get_drvdata(dev); @@ -107,7 +95,7 @@ static int ds1390_get_datetime(struct device *dev, struct rtc_time *dt) return rtc_valid_tm(dt); } -static int ds1390_set_datetime(struct device *dev, struct rtc_time *dt) +static int ds1390_set_time(struct device *dev, struct rtc_time *dt) { struct spi_device *spi = to_spi_device(dev); struct ds1390 *chip = dev_get_drvdata(dev); @@ -127,16 +115,6 @@ static int ds1390_set_datetime(struct device *dev, struct rtc_time *dt) return spi_write_then_read(spi, chip->txrx_buf, 8, NULL, 0); } -static int ds1390_read_time(struct device *dev, struct rtc_time *tm) -{ - return ds1390_get_datetime(dev, tm); -} - -static int ds1390_set_time(struct device *dev, struct rtc_time *tm) -{ - return ds1390_set_datetime(dev, tm); -} - static const struct rtc_class_ops ds1390_rtc_ops = { .read_time = ds1390_read_time, .set_time = ds1390_set_time, @@ -149,46 +127,40 @@ static int __devinit ds1390_probe(struct spi_device *spi) struct ds1390 *chip; int res; - printk(KERN_DEBUG "DS1390 SPI RTC driver\n"); - - rtc = rtc_device_register("ds1390", - &spi->dev, &ds1390_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - printk(KERN_ALERT "RTC : unable to register device\n"); - return PTR_ERR(rtc); - } - spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); chip = kzalloc(sizeof *chip, GFP_KERNEL); if (!chip) { - printk(KERN_ALERT "RTC : unable to allocate device memory\n"); - rtc_device_unregister(rtc); + dev_err(&spi->dev, "unable to allocate device memory\n"); return -ENOMEM; } - chip->rtc = rtc; dev_set_drvdata(&spi->dev, chip); res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp); - if (res) { - printk(KERN_ALERT "RTC : unable to read device\n"); - rtc_device_unregister(rtc); + if (res != 0) { + dev_err(&spi->dev, "unable to read device\n"); + kfree(chip); return res; } - return 0; + chip->rtc = rtc_device_register("ds1390", + &spi->dev, &ds1390_rtc_ops, THIS_MODULE); + if (IS_ERR(chip->rtc)) { + dev_err(&spi->dev, "unable to register device\n"); + res = PTR_ERR(chip->rtc); + kfree(chip); + } + + return res; } static int __devexit ds1390_remove(struct spi_device *spi) { struct ds1390 *chip = platform_get_drvdata(spi); - struct rtc_device *rtc = chip->rtc; - - if (rtc) - rtc_device_unregister(rtc); + rtc_device_unregister(chip->rtc); kfree(chip); return 0; @@ -215,6 +187,6 @@ static __exit void ds1390_exit(void) } module_exit(ds1390_exit); -MODULE_DESCRIPTION("DS1390/93/94 SPI RTC driver"); +MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver"); MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 25caada78398..23a07fe15a2c 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -326,9 +326,9 @@ ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) { + if (pdata->irq <= 0) return -EINVAL; - } + pdata->alrm_mday = alrm->time.tm_mday; pdata->alrm_hour = alrm->time.tm_hour; pdata->alrm_min = alrm->time.tm_min; @@ -346,9 +346,9 @@ ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) { + if (pdata->irq <= 0) return -EINVAL; - } + alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; @@ -385,7 +385,7 @@ ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) { + if (pdata->irq <= 0) { return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ } switch (cmd) { @@ -503,7 +503,6 @@ ds1511_rtc_probe(struct platform_device *pdev) if (!pdata) { return -ENOMEM; } - pdata->irq = -1; pdata->size = res->end - res->start + 1; if (!request_mem_region(res->start, pdata->size, pdev->name)) { ret = -EBUSY; @@ -545,13 +544,13 @@ ds1511_rtc_probe(struct platform_device *pdev) * if the platform has an interrupt in mind for this device, * then by all means, set it */ - if (pdata->irq >= 0) { + if (pdata->irq > 0) { rtc_read(RTC_CMD1); if (request_irq(pdata->irq, ds1511_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; + pdata->irq = 0; } } @@ -572,7 +571,7 @@ ds1511_rtc_probe(struct platform_device *pdev) if (pdata->rtc) { rtc_device_unregister(pdata->rtc); } - if (pdata->irq >= 0) { + if (pdata->irq > 0) { free_irq(pdata->irq, pdev); } if (ds1511_base) { @@ -595,7 +594,7 @@ ds1511_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); rtc_device_unregister(pdata->rtc); pdata->rtc = NULL; - if (pdata->irq >= 0) { + if (pdata->irq > 0) { /* * disable the alarm interrupt */ diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index b9475cd20210..38d472b63406 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -162,7 +162,7 @@ static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; pdata->alrm_mday = alrm->time.tm_mday; pdata->alrm_hour = alrm->time.tm_hour; @@ -179,7 +179,7 @@ static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; @@ -213,7 +213,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ switch (cmd) { case RTC_AIE_OFF: @@ -301,7 +301,6 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->irq = -1; if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { ret = -EBUSY; goto out; @@ -327,13 +326,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) dev_warn(&pdev->dev, "voltage-low detected.\n"); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); if (request_irq(pdata->irq, ds1553_rtc_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; + pdata->irq = 0; } } @@ -353,7 +352,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) out: if (pdata->rtc) rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) + if (pdata->irq > 0) free_irq(pdata->irq, pdev); if (ioaddr) iounmap(ioaddr); @@ -369,7 +368,7 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, pdata->ioaddr + RTC_INTERRUPTS); free_irq(pdata->irq, pdev); } diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 4e91419e8911..06dfb54f99b6 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -83,32 +83,11 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) return 0; } -static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm) -{ - unsigned long secs; - - dev_dbg(&client->dev, - "%s: secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - - rtc_tm_to_time(tm, &secs); - - return ds1672_set_mmss(client, secs); -} - static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm) { return ds1672_get_datetime(to_i2c_client(dev), tm); } -static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return ds1672_set_datetime(to_i2c_client(dev), tm); -} - static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs) { return ds1672_set_mmss(to_i2c_client(dev), secs); @@ -152,7 +131,6 @@ static DEVICE_ATTR(control, S_IRUGO, show_control, NULL); static const struct rtc_class_ops ds1672_rtc_ops = { .read_time = ds1672_rtc_read_time, - .set_time = ds1672_rtc_set_time, .set_mmss = ds1672_rtc_set_mmss, }; diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c index 45e5b106af73..c51589ede5b7 100644 --- a/drivers/rtc/rtc-ds3234.c +++ b/drivers/rtc/rtc-ds3234.c @@ -1,4 +1,4 @@ -/* drivers/rtc/rtc-ds3234.c +/* rtc-ds3234.c * * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal * and SRAM. @@ -9,13 +9,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Changelog: - * - * 07-May-2008: Dennis Aberilla <denzzzhome@yahoo.com> - * - Created based on the max6902 code. Only implements the - * date/time keeping functions; no SRAM yet. */ +#include <linux/init.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/rtc.h> @@ -34,16 +31,7 @@ #define DS3234_REG_CONTROL 0x0E #define DS3234_REG_CONT_STAT 0x0F -#undef DS3234_DEBUG - -struct ds3234 { - struct rtc_device *rtc; - u8 buf[8]; /* Burst read: addr + 7 regs */ - u8 tx_buf[2]; - u8 rx_buf[2]; -}; - -static void ds3234_set_reg(struct device *dev, unsigned char address, +static int ds3234_set_reg(struct device *dev, unsigned char address, unsigned char data) { struct spi_device *spi = to_spi_device(dev); @@ -53,107 +41,45 @@ static void ds3234_set_reg(struct device *dev, unsigned char address, buf[0] = address | 0x80; buf[1] = data; - spi_write(spi, buf, 2); + return spi_write_then_read(spi, buf, 2, NULL, 0); } static int ds3234_get_reg(struct device *dev, unsigned char address, unsigned char *data) { struct spi_device *spi = to_spi_device(dev); - struct ds3234 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; - - if (!data) - return -EINVAL; - - /* Build our spi message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - - /* Address + dummy tx byte */ - xfer.len = 2; - xfer.tx_buf = chip->tx_buf; - xfer.rx_buf = chip->rx_buf; - - chip->tx_buf[0] = address; - chip->tx_buf[1] = 0xff; - spi_message_add_tail(&xfer, &message); + *data = address & 0x7f; - /* do the i/o */ - status = spi_sync(spi, &message); - if (status == 0) - status = message.status; - else - return status; - - *data = chip->rx_buf[1]; - - return status; + return spi_write_then_read(spi, data, 1, data, 1); } -static int ds3234_get_datetime(struct device *dev, struct rtc_time *dt) +static int ds3234_read_time(struct device *dev, struct rtc_time *dt) { + int err; + unsigned char buf[8]; struct spi_device *spi = to_spi_device(dev); - struct ds3234 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; - - /* build the message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - xfer.len = 1 + 7; /* Addr + 7 registers */ - xfer.tx_buf = chip->buf; - xfer.rx_buf = chip->buf; - chip->buf[0] = 0x00; /* Start address */ - spi_message_add_tail(&xfer, &message); - - /* do the i/o */ - status = spi_sync(spi, &message); - if (status == 0) - status = message.status; - else - return status; - /* Seconds, Minutes, Hours, Day, Date, Month, Year */ - dt->tm_sec = bcd2bin(chip->buf[1]); - dt->tm_min = bcd2bin(chip->buf[2]); - dt->tm_hour = bcd2bin(chip->buf[3] & 0x3f); - dt->tm_wday = bcd2bin(chip->buf[4]) - 1; /* 0 = Sun */ - dt->tm_mday = bcd2bin(chip->buf[5]); - dt->tm_mon = bcd2bin(chip->buf[6] & 0x1f) - 1; /* 0 = Jan */ - dt->tm_year = bcd2bin(chip->buf[7] & 0xff) + 100; /* Assume 20YY */ - -#ifdef DS3234_DEBUG - dev_dbg(dev, "\n%s : Read RTC values\n", __func__); - dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); - dev_dbg(dev, "tm_min : %i\n", dt->tm_min); - dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); - dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); - dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); - dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); - dev_dbg(dev, "tm_year: %i\n", dt->tm_year); -#endif + buf[0] = 0x00; /* Start address */ - return 0; + err = spi_write_then_read(spi, buf, 1, buf, 8); + if (err != 0) + return err; + + /* Seconds, Minutes, Hours, Day, Date, Month, Year */ + dt->tm_sec = bcd2bin(buf[0]); + dt->tm_min = bcd2bin(buf[1]); + dt->tm_hour = bcd2bin(buf[2] & 0x3f); + dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */ + dt->tm_mday = bcd2bin(buf[4]); + dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */ + dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */ + + return rtc_valid_tm(dt); } -static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt) +static int ds3234_set_time(struct device *dev, struct rtc_time *dt) { -#ifdef DS3234_DEBUG - dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); - dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); - dev_dbg(dev, "tm_min : %i\n", dt->tm_min); - dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); - dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); - dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); - dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); - dev_dbg(dev, "tm_year: %i\n", dt->tm_year); -#endif - ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec)); ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min)); ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f); @@ -174,16 +100,6 @@ static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt) return 0; } -static int ds3234_read_time(struct device *dev, struct rtc_time *tm) -{ - return ds3234_get_datetime(dev, tm); -} - -static int ds3234_set_time(struct device *dev, struct rtc_time *tm) -{ - return ds3234_set_datetime(dev, tm); -} - static const struct rtc_class_ops ds3234_rtc_ops = { .read_time = ds3234_read_time, .set_time = ds3234_set_time, @@ -193,31 +109,15 @@ static int __devinit ds3234_probe(struct spi_device *spi) { struct rtc_device *rtc; unsigned char tmp; - struct ds3234 *chip; int res; - rtc = rtc_device_register("ds3234", - &spi->dev, &ds3234_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); - chip = kzalloc(sizeof(struct ds3234), GFP_KERNEL); - if (!chip) { - rtc_device_unregister(rtc); - return -ENOMEM; - } - chip->rtc = rtc; - dev_set_drvdata(&spi->dev, chip); - res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp); - if (res) { - rtc_device_unregister(rtc); + if (res != 0) return res; - } /* Control settings * @@ -246,26 +146,27 @@ static int __devinit ds3234_probe(struct spi_device *spi) ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); + rtc = rtc_device_register("ds3234", + &spi->dev, &ds3234_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + dev_set_drvdata(&spi->dev, rtc); + return 0; } static int __devexit ds3234_remove(struct spi_device *spi) { - struct ds3234 *chip = platform_get_drvdata(spi); - struct rtc_device *rtc = chip->rtc; - - if (rtc) - rtc_device_unregister(rtc); - - kfree(chip); + struct rtc_device *rtc = platform_get_drvdata(spi); + rtc_device_unregister(rtc); return 0; } static struct spi_driver ds3234_driver = { .driver = { .name = "ds3234", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ds3234_probe, @@ -274,7 +175,6 @@ static struct spi_driver ds3234_driver = { static __init int ds3234_init(void) { - printk(KERN_INFO "DS3234 SPI RTC Driver\n"); return spi_register_driver(&ds3234_driver); } module_init(ds3234_init); diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 36e4ac0bd69c..f7a3283dd029 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -49,18 +49,6 @@ static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) return 0; } -static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - int err; - unsigned long secs; - - err = rtc_tm_to_time(tm, &secs); - if (err != 0) - return err; - - return ep93xx_rtc_set_mmss(dev, secs); -} - static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned short preload, delete; @@ -75,7 +63,6 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) static const struct rtc_class_ops ep93xx_rtc_ops = { .read_time = ep93xx_rtc_read_time, - .set_time = ep93xx_rtc_set_time, .set_mmss = ep93xx_rtc_set_mmss, .proc = ep93xx_rtc_proc, }; diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 43afb7ab5289..33921a6b1707 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -450,7 +450,7 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) * the mode without IRQ. */ m48t59->irq = platform_get_irq(pdev, 0); - if (m48t59->irq < 0) + if (m48t59->irq <= 0) m48t59->irq = NO_IRQ; if (m48t59->irq != NO_IRQ) { diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 2f6507df7b49..36a8ea9ed8ba 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -9,14 +9,6 @@ * * Driver for MAX6902 spi RTC * - * Changelog: - * - * 24-May-2006: Raphael Assenat <raph@8d.com> - * - Major rework - * Converted to rtc_device and uses the SPI layer. - * - * ??-???-2005: Someone at Compulab - * - Initial driver creation. */ #include <linux/module.h> @@ -26,7 +18,6 @@ #include <linux/rtc.h> #include <linux/spi/spi.h> #include <linux/bcd.h> -#include <linux/delay.h> #define MAX6902_REG_SECONDS 0x01 #define MAX6902_REG_MINUTES 0x03 @@ -38,16 +29,7 @@ #define MAX6902_REG_CONTROL 0x0F #define MAX6902_REG_CENTURY 0x13 -#undef MAX6902_DEBUG - -struct max6902 { - struct rtc_device *rtc; - u8 buf[9]; /* Burst read cmd + 8 registers */ - u8 tx_buf[2]; - u8 rx_buf[2]; -}; - -static void max6902_set_reg(struct device *dev, unsigned char address, +static int max6902_set_reg(struct device *dev, unsigned char address, unsigned char data) { struct spi_device *spi = to_spi_device(dev); @@ -57,113 +39,58 @@ static void max6902_set_reg(struct device *dev, unsigned char address, buf[0] = address & 0x7f; buf[1] = data; - spi_write(spi, buf, 2); + return spi_write_then_read(spi, buf, 2, NULL, 0); } static int max6902_get_reg(struct device *dev, unsigned char address, unsigned char *data) { struct spi_device *spi = to_spi_device(dev); - struct max6902 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; - - if (!data) - return -EINVAL; - - /* Build our spi message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - xfer.len = 2; - /* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */ - xfer.tx_buf = chip->tx_buf; - xfer.rx_buf = chip->rx_buf; /* Set MSB to indicate read */ - chip->tx_buf[0] = address | 0x80; - - spi_message_add_tail(&xfer, &message); + *data = address | 0x80; - /* do the i/o */ - status = spi_sync(spi, &message); - - if (status == 0) - *data = chip->rx_buf[1]; - return status; + return spi_write_then_read(spi, data, 1, data, 1); } -static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) +static int max6902_read_time(struct device *dev, struct rtc_time *dt) { - unsigned char tmp; - int century; - int err; + int err, century; struct spi_device *spi = to_spi_device(dev); - struct max6902 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; + unsigned char buf[8]; - err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp); - if (err) - return err; - - /* build the message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - xfer.len = 1 + 7; /* Burst read command + 7 registers */ - xfer.tx_buf = chip->buf; - xfer.rx_buf = chip->buf; - chip->buf[0] = 0xbf; /* Burst read */ - spi_message_add_tail(&xfer, &message); + buf[0] = 0xbf; /* Burst read */ - /* do the i/o */ - status = spi_sync(spi, &message); - if (status) - return status; + err = spi_write_then_read(spi, buf, 1, buf, 8); + if (err != 0) + return err; /* The chip sends data in this order: * Seconds, Minutes, Hours, Date, Month, Day, Year */ - dt->tm_sec = bcd2bin(chip->buf[1]); - dt->tm_min = bcd2bin(chip->buf[2]); - dt->tm_hour = bcd2bin(chip->buf[3]); - dt->tm_mday = bcd2bin(chip->buf[4]); - dt->tm_mon = bcd2bin(chip->buf[5]) - 1; - dt->tm_wday = bcd2bin(chip->buf[6]); - dt->tm_year = bcd2bin(chip->buf[7]); + dt->tm_sec = bcd2bin(buf[0]); + dt->tm_min = bcd2bin(buf[1]); + dt->tm_hour = bcd2bin(buf[2]); + dt->tm_mday = bcd2bin(buf[3]); + dt->tm_mon = bcd2bin(buf[4]) - 1; + dt->tm_wday = bcd2bin(buf[5]); + dt->tm_year = bcd2bin(buf[6]); + + /* Read century */ + err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &buf[0]); + if (err != 0) + return err; - century = bcd2bin(tmp) * 100; + century = bcd2bin(buf[0]) * 100; dt->tm_year += century; dt->tm_year -= 1900; -#ifdef MAX6902_DEBUG - printk("\n%s : Read RTC values\n",__func__); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_year: %i\n",dt->tm_year); - printk("tm_mon : %i\n",dt->tm_mon); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); -#endif - - return 0; + return rtc_valid_tm(dt); } -static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) +static int max6902_set_time(struct device *dev, struct rtc_time *dt) { - dt->tm_year = dt->tm_year+1900; - -#ifdef MAX6902_DEBUG - printk("\n%s : Setting RTC values\n",__func__); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); - printk("tm_year: %i\n",dt->tm_year); -#endif + dt->tm_year = dt->tm_year + 1900; /* Remove write protection */ max6902_set_reg(dev, 0xF, 0); @@ -173,10 +100,10 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) max6902_set_reg(dev, 0x05, bin2bcd(dt->tm_hour)); max6902_set_reg(dev, 0x07, bin2bcd(dt->tm_mday)); - max6902_set_reg(dev, 0x09, bin2bcd(dt->tm_mon+1)); + max6902_set_reg(dev, 0x09, bin2bcd(dt->tm_mon + 1)); max6902_set_reg(dev, 0x0B, bin2bcd(dt->tm_wday)); - max6902_set_reg(dev, 0x0D, bin2bcd(dt->tm_year%100)); - max6902_set_reg(dev, 0x13, bin2bcd(dt->tm_year/100)); + max6902_set_reg(dev, 0x0D, bin2bcd(dt->tm_year % 100)); + max6902_set_reg(dev, 0x13, bin2bcd(dt->tm_year / 100)); /* Compulab used a delay here. However, the datasheet * does not mention a delay being required anywhere... */ @@ -188,16 +115,6 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) return 0; } -static int max6902_read_time(struct device *dev, struct rtc_time *tm) -{ - return max6902_get_datetime(dev, tm); -} - -static int max6902_set_time(struct device *dev, struct rtc_time *tm) -{ - return max6902_set_datetime(dev, tm); -} - static const struct rtc_class_ops max6902_rtc_ops = { .read_time = max6902_read_time, .set_time = max6902_set_time, @@ -207,45 +124,29 @@ static int __devinit max6902_probe(struct spi_device *spi) { struct rtc_device *rtc; unsigned char tmp; - struct max6902 *chip; int res; - rtc = rtc_device_register("max6902", - &spi->dev, &max6902_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); - chip = kzalloc(sizeof *chip, GFP_KERNEL); - if (!chip) { - rtc_device_unregister(rtc); - return -ENOMEM; - } - chip->rtc = rtc; - dev_set_drvdata(&spi->dev, chip); - res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp); - if (res) { - rtc_device_unregister(rtc); + if (res != 0) return res; - } + + rtc = rtc_device_register("max6902", + &spi->dev, &max6902_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); return 0; } static int __devexit max6902_remove(struct spi_device *spi) { - struct max6902 *chip = platform_get_drvdata(spi); - struct rtc_device *rtc = chip->rtc; - - if (rtc) - rtc_device_unregister(rtc); - - kfree(chip); + struct rtc_device *rtc = platform_get_drvdata(spi); + rtc_device_unregister(rtc); return 0; } @@ -261,7 +162,6 @@ static struct spi_driver max6902_driver = { static __init int max6902_init(void) { - printk("max6902 spi driver\n"); return spi_register_driver(&max6902_driver); } module_init(max6902_init); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c new file mode 100644 index 000000000000..45f12dcd3716 --- /dev/null +++ b/drivers/rtc/rtc-mv.c @@ -0,0 +1,163 @@ +/* + * Driver for the RTC in Marvell SoCs. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/io.h> +#include <linux/platform_device.h> + + +#define RTC_TIME_REG_OFFS 0 +#define RTC_SECONDS_OFFS 0 +#define RTC_MINUTES_OFFS 8 +#define RTC_HOURS_OFFS 16 +#define RTC_WDAY_OFFS 24 +#define RTC_HOURS_12H_MODE (1 << 22) /* 12 hours mode */ + +#define RTC_DATE_REG_OFFS 4 +#define RTC_MDAY_OFFS 0 +#define RTC_MONTH_OFFS 8 +#define RTC_YEAR_OFFS 16 + + +struct rtc_plat_data { + struct rtc_device *rtc; + void __iomem *ioaddr; +}; + +static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rtc_plat_data *pdata = dev_get_drvdata(dev); + void __iomem *ioaddr = pdata->ioaddr; + u32 rtc_reg; + + rtc_reg = (bin2bcd(tm->tm_sec) << RTC_SECONDS_OFFS) | + (bin2bcd(tm->tm_min) << RTC_MINUTES_OFFS) | + (bin2bcd(tm->tm_hour) << RTC_HOURS_OFFS) | + (bin2bcd(tm->tm_wday) << RTC_WDAY_OFFS); + writel(rtc_reg, ioaddr + RTC_TIME_REG_OFFS); + + rtc_reg = (bin2bcd(tm->tm_mday) << RTC_MDAY_OFFS) | + (bin2bcd(tm->tm_mon + 1) << RTC_MONTH_OFFS) | + (bin2bcd(tm->tm_year % 100) << RTC_YEAR_OFFS); + writel(rtc_reg, ioaddr + RTC_DATE_REG_OFFS); + + return 0; +} + +static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rtc_plat_data *pdata = dev_get_drvdata(dev); + void __iomem *ioaddr = pdata->ioaddr; + u32 rtc_time, rtc_date; + unsigned int year, month, day, hour, minute, second, wday; + + rtc_time = readl(ioaddr + RTC_TIME_REG_OFFS); + rtc_date = readl(ioaddr + RTC_DATE_REG_OFFS); + + second = rtc_time & 0x7f; + minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f; + hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */ + wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7; + + day = rtc_date & 0x3f; + month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f; + year = (rtc_date >> RTC_YEAR_OFFS) & 0xff; + + tm->tm_sec = bcd2bin(second); + tm->tm_min = bcd2bin(minute); + tm->tm_hour = bcd2bin(hour); + tm->tm_mday = bcd2bin(day); + tm->tm_wday = bcd2bin(wday); + tm->tm_mon = bcd2bin(month) - 1; + /* hw counts from year 2000, but tm_year is relative to 1900 */ + tm->tm_year = bcd2bin(year) + 100; + + return rtc_valid_tm(tm); +} + +static const struct rtc_class_ops mv_rtc_ops = { + .read_time = mv_rtc_read_time, + .set_time = mv_rtc_set_time, +}; + +static int __init mv_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct rtc_plat_data *pdata; + resource_size_t size; + u32 rtc_time; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + size = resource_size(res); + if (!devm_request_mem_region(&pdev->dev, res->start, size, + pdev->name)) + return -EBUSY; + + pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, size); + if (!pdata->ioaddr) + return -ENOMEM; + + /* make sure the 24 hours mode is enabled */ + rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS); + if (rtc_time & RTC_HOURS_12H_MODE) { + dev_err(&pdev->dev, "24 Hours mode not supported.\n"); + return -EINVAL; + } + + platform_set_drvdata(pdev, pdata); + pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, + &mv_rtc_ops, THIS_MODULE); + if (IS_ERR(pdata->rtc)) + return PTR_ERR(pdata->rtc); + + return 0; +} + +static int __exit mv_rtc_remove(struct platform_device *pdev) +{ + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + rtc_device_unregister(pdata->rtc); + return 0; +} + +static struct platform_driver mv_rtc_driver = { + .remove = __exit_p(mv_rtc_remove), + .driver = { + .name = "rtc-mv", + .owner = THIS_MODULE, + }, +}; + +static __init int mv_init(void) +{ + return platform_driver_probe(&mv_rtc_driver, mv_rtc_probe); +} + +static __exit void mv_exit(void) +{ + platform_driver_unregister(&mv_rtc_driver); +} + +module_init(mv_init); +module_exit(mv_exit); + +MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>"); +MODULE_DESCRIPTION("Marvell RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtc-mv"); diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c new file mode 100644 index 000000000000..cc7eb8767b82 --- /dev/null +++ b/drivers/rtc/rtc-pxa.c @@ -0,0 +1,489 @@ +/* + * Real Time Clock interface for XScale PXA27x and PXA3xx + * + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/io.h> + +#define TIMER_FREQ CLOCK_TICK_RATE +#define RTC_DEF_DIVIDER (32768 - 1) +#define RTC_DEF_TRIM 0 +#define MAXFREQ_PERIODIC 1000 + +/* + * PXA Registers and bits definitions + */ +#define RTSR_PICE (1 << 15) /* Periodic interrupt count enable */ +#define RTSR_PIALE (1 << 14) /* Periodic interrupt Alarm enable */ +#define RTSR_PIAL (1 << 13) /* Periodic interrupt detected */ +#define RTSR_SWALE2 (1 << 11) /* RTC stopwatch alarm2 enable */ +#define RTSR_SWAL2 (1 << 10) /* RTC stopwatch alarm2 detected */ +#define RTSR_SWALE1 (1 << 9) /* RTC stopwatch alarm1 enable */ +#define RTSR_SWAL1 (1 << 8) /* RTC stopwatch alarm1 detected */ +#define RTSR_RDALE2 (1 << 7) /* RTC alarm2 enable */ +#define RTSR_RDAL2 (1 << 6) /* RTC alarm2 detected */ +#define RTSR_RDALE1 (1 << 5) /* RTC alarm1 enable */ +#define RTSR_RDAL1 (1 << 4) /* RTC alarm1 detected */ +#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ +#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ +#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ +#define RTSR_AL (1 << 0) /* RTC alarm detected */ +#define RTSR_TRIG_MASK (RTSR_AL | RTSR_HZ | RTSR_RDAL1 | RTSR_RDAL2\ + | RTSR_SWAL1 | RTSR_SWAL2) +#define RYxR_YEAR_S 9 +#define RYxR_YEAR_MASK (0xfff << RYxR_YEAR_S) +#define RYxR_MONTH_S 5 +#define RYxR_MONTH_MASK (0xf << RYxR_MONTH_S) +#define RYxR_DAY_MASK 0x1f +#define RDxR_HOUR_S 12 +#define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S) +#define RDxR_MIN_S 6 +#define RDxR_MIN_MASK (0x3f << RDxR_MIN_S) +#define RDxR_SEC_MASK 0x3f + +#define RTSR 0x08 +#define RTTR 0x0c +#define RDCR 0x10 +#define RYCR 0x14 +#define RDAR1 0x18 +#define RYAR1 0x1c +#define RTCPICR 0x34 +#define PIAR 0x38 + +#define rtc_readl(pxa_rtc, reg) \ + __raw_readl((pxa_rtc)->base + (reg)) +#define rtc_writel(pxa_rtc, reg, value) \ + __raw_writel((value), (pxa_rtc)->base + (reg)) + +struct pxa_rtc { + struct resource *ress; + void __iomem *base; + int irq_1Hz; + int irq_Alrm; + struct rtc_device *rtc; + spinlock_t lock; /* Protects this structure */ + struct rtc_time rtc_alarm; +}; + +static u32 ryxr_calc(struct rtc_time *tm) +{ + return ((tm->tm_year + 1900) << RYxR_YEAR_S) + | ((tm->tm_mon + 1) << RYxR_MONTH_S) + | tm->tm_mday; +} + +static u32 rdxr_calc(struct rtc_time *tm) +{ + return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S) + | tm->tm_sec; +} + +static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm) +{ + tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900; + tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1; + tm->tm_mday = (rycr & RYxR_DAY_MASK); + tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S; + tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S; + tm->tm_sec = rdcr & RDxR_SEC_MASK; +} + +static void rtsr_clear_bits(struct pxa_rtc *pxa_rtc, u32 mask) +{ + u32 rtsr; + + rtsr = rtc_readl(pxa_rtc, RTSR); + rtsr &= ~RTSR_TRIG_MASK; + rtsr &= ~mask; + rtc_writel(pxa_rtc, RTSR, rtsr); +} + +static void rtsr_set_bits(struct pxa_rtc *pxa_rtc, u32 mask) +{ + u32 rtsr; + + rtsr = rtc_readl(pxa_rtc, RTSR); + rtsr &= ~RTSR_TRIG_MASK; + rtsr |= mask; + rtc_writel(pxa_rtc, RTSR, rtsr); +} + +static irqreturn_t pxa_rtc_irq(int irq, void *dev_id) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + u32 rtsr; + unsigned long events = 0; + + spin_lock(&pxa_rtc->lock); + + /* clear interrupt sources */ + rtsr = rtc_readl(pxa_rtc, RTSR); + rtc_writel(pxa_rtc, RTSR, rtsr); + + /* temporary disable rtc interrupts */ + rtsr_clear_bits(pxa_rtc, RTSR_RDALE1 | RTSR_PIALE | RTSR_HZE); + + /* clear alarm interrupt if it has occurred */ + if (rtsr & RTSR_RDAL1) + rtsr &= ~RTSR_RDALE1; + + /* update irq data & counter */ + if (rtsr & RTSR_RDAL1) + events |= RTC_AF | RTC_IRQF; + if (rtsr & RTSR_HZ) + events |= RTC_UF | RTC_IRQF; + if (rtsr & RTSR_PIAL) + events |= RTC_PF | RTC_IRQF; + + rtc_update_irq(pxa_rtc->rtc, 1, events); + + /* enable back rtc interrupts */ + rtc_writel(pxa_rtc, RTSR, rtsr & ~RTSR_TRIG_MASK); + + spin_unlock(&pxa_rtc->lock); + return IRQ_HANDLED; +} + +static int pxa_rtc_open(struct device *dev) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + int ret; + + ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, IRQF_DISABLED, + "rtc 1Hz", dev); + if (ret < 0) { + dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz, + ret); + goto err_irq_1Hz; + } + ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, IRQF_DISABLED, + "rtc Alrm", dev); + if (ret < 0) { + dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm, + ret); + goto err_irq_Alrm; + } + + return 0; + +err_irq_Alrm: + free_irq(pxa_rtc->irq_1Hz, dev); +err_irq_1Hz: + return ret; +} + +static void pxa_rtc_release(struct device *dev) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&pxa_rtc->lock); + rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); + spin_unlock_irq(&pxa_rtc->lock); + + free_irq(pxa_rtc->irq_Alrm, dev); + free_irq(pxa_rtc->irq_1Hz, dev); +} + +static int pxa_periodic_irq_set_freq(struct device *dev, int freq) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + int period_ms; + + if (freq < 1 || freq > MAXFREQ_PERIODIC) + return -EINVAL; + + period_ms = 1000 / freq; + rtc_writel(pxa_rtc, PIAR, period_ms); + + return 0; +} + +static int pxa_periodic_irq_set_state(struct device *dev, int enabled) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + if (enabled) + rtsr_set_bits(pxa_rtc, RTSR_PIALE | RTSR_PICE); + else + rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_PICE); + + return 0; +} + +static int pxa_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + int ret = 0; + + spin_lock_irq(&pxa_rtc->lock); + switch (cmd) { + case RTC_AIE_OFF: + rtsr_clear_bits(pxa_rtc, RTSR_RDALE1); + break; + case RTC_AIE_ON: + rtsr_set_bits(pxa_rtc, RTSR_RDALE1); + break; + case RTC_UIE_OFF: + rtsr_clear_bits(pxa_rtc, RTSR_HZE); + break; + case RTC_UIE_ON: + rtsr_set_bits(pxa_rtc, RTSR_HZE); + break; + default: + ret = -ENOIOCTLCMD; + } + + spin_unlock_irq(&pxa_rtc->lock); + return ret; +} + +static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + u32 rycr, rdcr; + + rycr = rtc_readl(pxa_rtc, RYCR); + rdcr = rtc_readl(pxa_rtc, RDCR); + + tm_calc(rycr, rdcr, tm); + return 0; +} + +static int pxa_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + rtc_writel(pxa_rtc, RYCR, ryxr_calc(tm)); + rtc_writel(pxa_rtc, RDCR, rdxr_calc(tm)); + + return 0; +} + +static int pxa_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + u32 rtsr, ryar, rdar; + + ryar = rtc_readl(pxa_rtc, RYAR1); + rdar = rtc_readl(pxa_rtc, RDAR1); + tm_calc(ryar, rdar, &alrm->time); + + rtsr = rtc_readl(pxa_rtc, RTSR); + alrm->enabled = (rtsr & RTSR_RDALE1) ? 1 : 0; + alrm->pending = (rtsr & RTSR_RDAL1) ? 1 : 0; + return 0; +} + +static int pxa_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + u32 rtsr; + + spin_lock_irq(&pxa_rtc->lock); + + rtc_writel(pxa_rtc, RYAR1, ryxr_calc(&alrm->time)); + rtc_writel(pxa_rtc, RDAR1, rdxr_calc(&alrm->time)); + + rtsr = rtc_readl(pxa_rtc, RTSR); + if (alrm->enabled) + rtsr |= RTSR_RDALE1; + else + rtsr &= ~RTSR_RDALE1; + rtc_writel(pxa_rtc, RTSR, rtsr); + + spin_unlock_irq(&pxa_rtc->lock); + + return 0; +} + +static int pxa_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + seq_printf(seq, "trim/divider\t: 0x%08x\n", rtc_readl(pxa_rtc, RTTR)); + seq_printf(seq, "update_IRQ\t: %s\n", + (rtc_readl(pxa_rtc, RTSR) & RTSR_HZE) ? "yes" : "no"); + seq_printf(seq, "periodic_IRQ\t: %s\n", + (rtc_readl(pxa_rtc, RTSR) & RTSR_PIALE) ? "yes" : "no"); + seq_printf(seq, "periodic_freq\t: %u\n", rtc_readl(pxa_rtc, PIAR)); + + return 0; +} + +static const struct rtc_class_ops pxa_rtc_ops = { + .open = pxa_rtc_open, + .release = pxa_rtc_release, + .ioctl = pxa_rtc_ioctl, + .read_time = pxa_rtc_read_time, + .set_time = pxa_rtc_set_time, + .read_alarm = pxa_rtc_read_alarm, + .set_alarm = pxa_rtc_set_alarm, + .proc = pxa_rtc_proc, + .irq_set_state = pxa_periodic_irq_set_state, + .irq_set_freq = pxa_periodic_irq_set_freq, +}; + +static int __init pxa_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pxa_rtc *pxa_rtc; + int ret; + u32 rttr; + + pxa_rtc = kzalloc(sizeof(struct pxa_rtc), GFP_KERNEL); + if (!pxa_rtc) + return -ENOMEM; + + spin_lock_init(&pxa_rtc->lock); + platform_set_drvdata(pdev, pxa_rtc); + + ret = -ENXIO; + pxa_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!pxa_rtc->ress) { + dev_err(dev, "No I/O memory resource defined\n"); + goto err_ress; + } + + pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0); + if (pxa_rtc->irq_1Hz < 0) { + dev_err(dev, "No 1Hz IRQ resource defined\n"); + goto err_ress; + } + pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1); + if (pxa_rtc->irq_Alrm < 0) { + dev_err(dev, "No alarm IRQ resource defined\n"); + goto err_ress; + } + + ret = -ENOMEM; + pxa_rtc->base = ioremap(pxa_rtc->ress->start, + resource_size(pxa_rtc->ress)); + if (!pxa_rtc->base) { + dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n"); + goto err_map; + } + + /* + * If the clock divider is uninitialized then reset it to the + * default value to get the 1Hz clock. + */ + if (rtc_readl(pxa_rtc, RTTR) == 0) { + rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + rtc_writel(pxa_rtc, RTTR, rttr); + dev_warn(dev, "warning: initializing default clock" + " divider/trim value\n"); + } + + rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); + + pxa_rtc->rtc = rtc_device_register("pxa-rtc", &pdev->dev, &pxa_rtc_ops, + THIS_MODULE); + ret = PTR_ERR(pxa_rtc->rtc); + if (IS_ERR(pxa_rtc->rtc)) { + dev_err(dev, "Failed to register RTC device -> %d\n", ret); + goto err_rtc_reg; + } + + device_init_wakeup(dev, 1); + + return 0; + +err_rtc_reg: + iounmap(pxa_rtc->base); +err_ress: +err_map: + kfree(pxa_rtc); + return ret; +} + +static int __exit pxa_rtc_remove(struct platform_device *pdev) +{ + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(pxa_rtc->rtc); + + spin_lock_irq(&pxa_rtc->lock); + iounmap(pxa_rtc->base); + spin_unlock_irq(&pxa_rtc->lock); + + kfree(pxa_rtc); + + return 0; +} + +#ifdef CONFIG_PM +static int pxa_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(pxa_rtc->irq_Alrm); + return 0; +} + +static int pxa_rtc_resume(struct platform_device *pdev) +{ + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(pxa_rtc->irq_Alrm); + return 0; +} +#else +#define pxa_rtc_suspend NULL +#define pxa_rtc_resume NULL +#endif + +static struct platform_driver pxa_rtc_driver = { + .remove = __exit_p(pxa_rtc_remove), + .suspend = pxa_rtc_suspend, + .resume = pxa_rtc_resume, + .driver = { + .name = "pxa-rtc", + }, +}; + +static int __init pxa_rtc_init(void) +{ + if (cpu_is_pxa27x() || cpu_is_pxa3xx()) + return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); + + return -ENODEV; +} + +static void __exit pxa_rtc_exit(void) +{ + platform_driver_unregister(&pxa_rtc_driver); +} + +module_init(pxa_rtc_init); +module_exit(pxa_rtc_exit); + +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_DESCRIPTION("PXA27x/PXA3xx Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa-rtc"); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7a568beba3f0..e0d7b9991505 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -94,6 +94,9 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) { unsigned int tmp; + if (!is_power_of_2(freq)) + return -EINVAL; + spin_lock_irq(&s3c_rtc_pie_lock); tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index aaf9d6a337cc..1c3fc6b428e9 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/io.h> +#include <linux/log2.h> #include <asm/rtc.h> #define DRV_NAME "sh-rtc" @@ -89,7 +90,9 @@ struct sh_rtc { void __iomem *regbase; unsigned long regsize; struct resource *res; - unsigned int alarm_irq, periodic_irq, carry_irq; + int alarm_irq; + int periodic_irq; + int carry_irq; struct rtc_device *rtc_dev; spinlock_t lock; unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ @@ -549,6 +552,8 @@ static int sh_rtc_irq_set_state(struct device *dev, int enabled) static int sh_rtc_irq_set_freq(struct device *dev, int freq) { + if (!is_power_of_2(freq)) + return -EINVAL; return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq); } @@ -578,7 +583,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) /* get periodic/carry/alarm irqs */ ret = platform_get_irq(pdev, 0); - if (unlikely(ret < 0)) { + if (unlikely(ret <= 0)) { ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for period\n"); goto err_badres; @@ -586,7 +591,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) rtc->periodic_irq = ret; ret = platform_get_irq(pdev, 1); - if (unlikely(ret < 0)) { + if (unlikely(ret <= 0)) { ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for carry\n"); goto err_badres; @@ -594,7 +599,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) rtc->carry_irq = ret; ret = platform_get_irq(pdev, 2); - if (unlikely(ret < 0)) { + if (unlikely(ret <= 0)) { ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for alarm\n"); goto err_badres; diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index f4cd46e15af9..dc0b6224ad9b 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -170,7 +170,7 @@ static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; pdata->alrm_mday = alrm->time.tm_mday; pdata->alrm_hour = alrm->time.tm_hour; @@ -187,7 +187,7 @@ static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; @@ -221,7 +221,7 @@ static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ switch (cmd) { case RTC_AIE_OFF: @@ -303,7 +303,6 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->irq = -1; if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { ret = -EBUSY; goto out; @@ -329,13 +328,13 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) dev_warn(&pdev->dev, "voltage-low detected.\n"); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; + pdata->irq = 0; } } @@ -355,7 +354,7 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) out: if (pdata->rtc) rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) + if (pdata->irq > 0) free_irq(pdata->irq, pdev); if (ioaddr) iounmap(ioaddr); @@ -371,7 +370,7 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, pdata->ioaddr + RTC_INTERRUPTS); free_irq(pdata->irq, pdev); } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index bc930022004a..e478280ff628 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -34,14 +34,9 @@ static int test_rtc_read_time(struct device *dev, return 0; } -static int test_rtc_set_time(struct device *dev, - struct rtc_time *tm) -{ - return 0; -} - static int test_rtc_set_mmss(struct device *dev, unsigned long secs) { + dev_info(dev, "%s, secs = %lu\n", __func__, secs); return 0; } @@ -78,7 +73,6 @@ static int test_rtc_ioctl(struct device *dev, unsigned int cmd, static const struct rtc_class_ops test_rtc_ops = { .proc = test_rtc_proc, .read_time = test_rtc_read_time, - .set_time = test_rtc_set_time, .read_alarm = test_rtc_read_alarm, .set_alarm = test_rtc_set_alarm, .set_mmss = test_rtc_set_mmss, diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c index 01d8da9afdc8..8ce5f74ee45b 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl4030.c @@ -19,6 +19,7 @@ */ #include <linux/kernel.h> +#include <linux/errno.h> #include <linux/init.h> #include <linux/module.h> #include <linux/types.h> @@ -415,8 +416,8 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) int irq = platform_get_irq(pdev, 0); u8 rd_reg; - if (irq < 0) - return irq; + if (irq <= 0) + return -EINVAL; rtc = rtc_device_register(pdev->name, &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c new file mode 100644 index 000000000000..4ee4857ff207 --- /dev/null +++ b/drivers/rtc/rtc-tx4939.c @@ -0,0 +1,317 @@ +/* + * TX4939 internal RTC driver + * Based on RBTX49xx patch from CELF patch archive. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright TOSHIBA CORPORATION 2005-2007 + */ +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <asm/txx9/tx4939.h> + +struct tx4939rtc_plat_data { + struct rtc_device *rtc; + struct tx4939_rtc_reg __iomem *rtcreg; +}; + +static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) +{ + return platform_get_drvdata(to_platform_device(dev)); +} + +static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd) +{ + int i = 0; + + __raw_writel(cmd, &rtcreg->ctl); + /* This might take 30us (next 32.768KHz clock) */ + while (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_BUSY) { + /* timeout on approx. 100us (@ GBUS200MHz) */ + if (i++ > 200 * 100) + return -EBUSY; + cpu_relax(); + } + return 0; +} + +static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned char buf[6]; + + buf[0] = 0; + buf[1] = 0; + buf[2] = secs; + buf[3] = secs >> 8; + buf[4] = secs >> 16; + buf[5] = secs >> 24; + spin_lock_irq(&pdata->rtc->irq_lock); + __raw_writel(0, &rtcreg->adr); + for (i = 0; i < 6; i++) + __raw_writel(buf[i], &rtcreg->dat); + ret = tx4939_rtc_cmd(rtcreg, + TX4939_RTCCTL_COMMAND_SETTIME | + (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; +} + +static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned long sec; + unsigned char buf[6]; + + spin_lock_irq(&pdata->rtc->irq_lock); + ret = tx4939_rtc_cmd(rtcreg, + TX4939_RTCCTL_COMMAND_GETTIME | + (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); + if (ret) { + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; + } + __raw_writel(2, &rtcreg->adr); + for (i = 2; i < 6; i++) + buf[i] = __raw_readl(&rtcreg->dat); + spin_unlock_irq(&pdata->rtc->irq_lock); + sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + rtc_time_to_tm(sec, tm); + return rtc_valid_tm(tm); +} + +static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned long sec; + unsigned char buf[6]; + + if (alrm->time.tm_sec < 0 || + alrm->time.tm_min < 0 || + alrm->time.tm_hour < 0 || + alrm->time.tm_mday < 0 || + alrm->time.tm_mon < 0 || + alrm->time.tm_year < 0) + return -EINVAL; + rtc_tm_to_time(&alrm->time, &sec); + buf[0] = 0; + buf[1] = 0; + buf[2] = sec; + buf[3] = sec >> 8; + buf[4] = sec >> 16; + buf[5] = sec >> 24; + spin_lock_irq(&pdata->rtc->irq_lock); + __raw_writel(0, &rtcreg->adr); + for (i = 0; i < 6; i++) + __raw_writel(buf[i], &rtcreg->dat); + ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM | + (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; +} + +static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned long sec; + unsigned char buf[6]; + u32 ctl; + + spin_lock_irq(&pdata->rtc->irq_lock); + ret = tx4939_rtc_cmd(rtcreg, + TX4939_RTCCTL_COMMAND_GETALARM | + (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); + if (ret) { + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; + } + __raw_writel(2, &rtcreg->adr); + for (i = 2; i < 6; i++) + buf[i] = __raw_readl(&rtcreg->dat); + ctl = __raw_readl(&rtcreg->ctl); + alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; + alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; + spin_unlock_irq(&pdata->rtc->irq_lock); + sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + rtc_time_to_tm(sec, &alrm->time); + return rtc_valid_tm(&alrm->time); +} + +static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + + spin_lock_irq(&pdata->rtc->irq_lock); + tx4939_rtc_cmd(pdata->rtcreg, + TX4939_RTCCTL_COMMAND_NOP | + (enabled ? TX4939_RTCCTL_ALME : 0)); + spin_unlock_irq(&pdata->rtc->irq_lock); + return 0; +} + +static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev_id); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + unsigned long events = RTC_IRQF; + + spin_lock(&pdata->rtc->irq_lock); + if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) { + events |= RTC_AF; + tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); + } + spin_unlock(&pdata->rtc->irq_lock); + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tx4939_rtc_ops = { + .read_time = tx4939_rtc_read_time, + .read_alarm = tx4939_rtc_read_alarm, + .set_alarm = tx4939_rtc_set_alarm, + .set_mmss = tx4939_rtc_set_mmss, + .alarm_irq_enable = tx4939_rtc_alarm_irq_enable, +}; + +static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + ssize_t count; + + spin_lock_irq(&pdata->rtc->irq_lock); + for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; + count++, size--) { + __raw_writel(pos++, &rtcreg->adr); + *buf++ = __raw_readl(&rtcreg->dat); + } + spin_unlock_irq(&pdata->rtc->irq_lock); + return count; +} + +static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + ssize_t count; + + spin_lock_irq(&pdata->rtc->irq_lock); + for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; + count++, size--) { + __raw_writel(pos++, &rtcreg->adr); + __raw_writel(*buf++, &rtcreg->dat); + } + spin_unlock_irq(&pdata->rtc->irq_lock); + return count; +} + +static struct bin_attribute tx4939_rtc_nvram_attr = { + .attr = { + .name = "nvram", + .mode = S_IRUGO | S_IWUSR, + }, + .size = TX4939_RTC_REG_RAMSIZE, + .read = tx4939_rtc_nvram_read, + .write = tx4939_rtc_nvram_write, +}; + +static int __init tx4939_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct tx4939rtc_plat_data *pdata; + struct resource *res; + int irq, ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + platform_set_drvdata(pdev, pdata); + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) + return -EBUSY; + pdata->rtcreg = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pdata->rtcreg) + return -EBUSY; + + tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); + if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, + IRQF_DISABLED | IRQF_SHARED, + pdev->name, &pdev->dev) < 0) { + return -EBUSY; + } + rtc = rtc_device_register(pdev->name, &pdev->dev, + &tx4939_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + pdata->rtc = rtc; + ret = sysfs_create_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); + if (ret) + rtc_device_unregister(rtc); + return ret; +} + +static int __exit tx4939_rtc_remove(struct platform_device *pdev) +{ + struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); + struct rtc_device *rtc = pdata->rtc; + + spin_lock_irq(&rtc->irq_lock); + tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); + spin_unlock_irq(&rtc->irq_lock); + sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); + rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver tx4939_rtc_driver = { + .remove = __exit_p(tx4939_rtc_remove), + .driver = { + .name = "tx4939rtc", + .owner = THIS_MODULE, + }, +}; + +static int __init tx4939rtc_init(void) +{ + return platform_driver_probe(&tx4939_rtc_driver, tx4939_rtc_probe); +} + +static void __exit tx4939rtc_exit(void) +{ + platform_driver_unregister(&tx4939_rtc_driver); +} + +module_init(tx4939rtc_init); +module_exit(tx4939rtc_exit); + +MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); +MODULE_DESCRIPTION("TX4939 internal RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tx4939rtc"); diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 834dcc6d785f..f11297aff854 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -27,6 +27,7 @@ #include <linux/rtc.h> #include <linux/spinlock.h> #include <linux/types.h> +#include <linux/log2.h> #include <asm/div64.h> #include <asm/io.h> @@ -84,8 +85,8 @@ static DEFINE_SPINLOCK(rtc_lock); static char rtc_name[] = "RTC"; static unsigned long periodic_count; static unsigned int alarm_enabled; -static int aie_irq = -1; -static int pie_irq = -1; +static int aie_irq; +static int pie_irq; static inline unsigned long read_elapsed_second(void) { @@ -210,6 +211,8 @@ static int vr41xx_rtc_irq_set_freq(struct device *dev, int freq) { unsigned long count; + if (!is_power_of_2(freq)) + return -EINVAL; count = RTC_FREQUENCY; do_div(count, freq); @@ -360,7 +363,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) spin_unlock_irq(&rtc_lock); aie_irq = platform_get_irq(pdev, 0); - if (aie_irq < 0 || aie_irq >= nr_irqs) { + if (aie_irq <= 0) { retval = -EBUSY; goto err_device_unregister; } @@ -371,7 +374,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) goto err_device_unregister; pie_irq = platform_get_irq(pdev, 1); - if (pie_irq < 0 || pie_irq >= nr_irqs) + if (pie_irq <= 0) goto err_free_irq; retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED, diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b9d0efb6803f..4a6fe01831a8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -78,7 +78,7 @@ config SPI_AU1550 will be called au1550_spi. config SPI_BITBANG - tristate "Bitbanging SPI master" + tristate "Utilities for Bitbanging SPI masters" help With a few GPIO pins, your system can bitbang the SPI protocol. Select this to get SPI support through I/O pins (GPIO, parallel @@ -100,6 +100,22 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_GPIO + tristate "GPIO-based bitbanging SPI Master" + depends on GENERIC_GPIO + select SPI_BITBANG + help + This simple GPIO bitbanging SPI master uses the arch-neutral GPIO + interface to manage MOSI, MISO, SCK, and chipselect signals. SPI + slaves connected to a bus using this driver are configured as usual, + except that the spi_board_info.controller_data holds the GPIO number + for the chipselect used by this controller driver. + + Note that this driver often won't achieve even 1 Mbit/sec speeds, + making it unusually slow for SPI. If your platform can inline + GPIO operations, you should be able to leverage that for better + speed with a custom version of this driver; see the source code. + config SPI_IMX tristate "Freescale iMX SPI controller" depends on ARCH_IMX && EXPERIMENTAL diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index ccf18de34e1e..5e9f521b8844 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 8abae4ad0fa5..5e39bac9c51b 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -30,13 +30,6 @@ * The core SPI transfer engine just talks to a register bank to set up * DMA transfers; transfer queue progress is driven by IRQs. The clock * framework provides the base clock, subdivided for each spi_device. - * - * Newer controllers, marked with "new_1" flag, have: - * - CR.LASTXFER - * - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero) - * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) - * - SPI_CSRx.CSAAT - * - SPI_CSRx.SBCR allows faster clocking */ struct atmel_spi { spinlock_t lock; @@ -45,7 +38,6 @@ struct atmel_spi { int irq; struct clk *clk; struct platform_device *pdev; - unsigned new_1:1; struct spi_device *stay; u8 stopping; @@ -59,10 +51,33 @@ struct atmel_spi { dma_addr_t buffer_dma; }; +/* Controller-specific per-slave state */ +struct atmel_spi_device { + unsigned int npcs_pin; + u32 csr; +}; + #define BUFFER_SIZE PAGE_SIZE #define INVALID_DMA_ADDRESS 0xffffffff /* + * Version 2 of the SPI controller has + * - CR.LASTXFER + * - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero) + * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) + * - SPI_CSRx.CSAAT + * - SPI_CSRx.SBCR allows faster clocking + * + * We can determine the controller version by reading the VERSION + * register, but I haven't checked that it exists on all chips, and + * this is cheaper anyway. + */ +static bool atmel_spi_is_v2(void) +{ + return !cpu_is_at91rm9200(); +} + +/* * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby * they assume that spi slave device state will not change on deselect, so * that automagic deselection is OK. ("NPCSx rises if no data is to be @@ -80,39 +95,58 @@ struct atmel_spi { * Master on Chip Select 0.") No workaround exists for that ... so for * nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH, * and (c) will trigger that first erratum in some cases. + * + * TODO: Test if the atmel_spi_is_v2() branch below works on + * AT91RM9200 if we use some other register than CSR0. However, don't + * do this unconditionally since AP7000 has an errata where the BITS + * field in CSR0 overrides all other CSRs. */ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { - unsigned gpio = (unsigned) spi->controller_data; + struct atmel_spi_device *asd = spi->controller_state; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; - int i; - u32 csr; - u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; - - /* Make sure clock polarity is correct */ - for (i = 0; i < spi->master->num_chipselect; i++) { - csr = spi_readl(as, CSR0 + 4 * i); - if ((csr ^ cpol) & SPI_BIT(CPOL)) - spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL)); - } - mr = spi_readl(as, MR); - mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); + if (atmel_spi_is_v2()) { + /* + * Always use CSR0. This ensures that the clock + * switches to the correct idle polarity before we + * toggle the CS. + */ + spi_writel(as, CSR0, asd->csr); + spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS) + | SPI_BIT(MSTR)); + mr = spi_readl(as, MR); + gpio_set_value(asd->npcs_pin, active); + } else { + u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; + int i; + u32 csr; + + /* Make sure clock polarity is correct */ + for (i = 0; i < spi->master->num_chipselect; i++) { + csr = spi_readl(as, CSR0 + 4 * i); + if ((csr ^ cpol) & SPI_BIT(CPOL)) + spi_writel(as, CSR0 + 4 * i, + csr ^ SPI_BIT(CPOL)); + } + + mr = spi_readl(as, MR); + mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); + if (spi->chip_select != 0) + gpio_set_value(asd->npcs_pin, active); + spi_writel(as, MR, mr); + } dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", - gpio, active ? " (high)" : "", + asd->npcs_pin, active ? " (high)" : "", mr); - - if (!(cpu_is_at91rm9200() && spi->chip_select == 0)) - gpio_set_value(gpio, active); - spi_writel(as, MR, mr); } static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { - unsigned gpio = (unsigned) spi->controller_data; + struct atmel_spi_device *asd = spi->controller_state; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; @@ -126,11 +160,11 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) } dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n", - gpio, active ? " (low)" : "", + asd->npcs_pin, active ? " (low)" : "", mr); - if (!(cpu_is_at91rm9200() && spi->chip_select == 0)) - gpio_set_value(gpio, !active); + if (atmel_spi_is_v2() || spi->chip_select != 0) + gpio_set_value(asd->npcs_pin, !active); } static inline int atmel_spi_xfer_is_last(struct spi_message *msg, @@ -502,6 +536,7 @@ atmel_spi_interrupt(int irq, void *dev_id) static int atmel_spi_setup(struct spi_device *spi) { struct atmel_spi *as; + struct atmel_spi_device *asd; u32 scbr, csr; unsigned int bits = spi->bits_per_word; unsigned long bus_hz; @@ -536,19 +571,16 @@ static int atmel_spi_setup(struct spi_device *spi) } /* see notes above re chipselect */ - if (cpu_is_at91rm9200() + if (!atmel_spi_is_v2() && spi->chip_select == 0 && (spi->mode & SPI_CS_HIGH)) { dev_dbg(&spi->dev, "setup: can't be active-high\n"); return -EINVAL; } - /* - * Pre-new_1 chips start out at half the peripheral - * bus speed. - */ + /* v1 chips start out at half the peripheral bus speed. */ bus_hz = clk_get_rate(as->clk); - if (!as->new_1) + if (!atmel_spi_is_v2()) bus_hz /= 2; if (spi->max_speed_hz) { @@ -589,11 +621,20 @@ static int atmel_spi_setup(struct spi_device *spi) /* chipselect must have been muxed as GPIO (e.g. in board setup) */ npcs_pin = (unsigned int)spi->controller_data; - if (!spi->controller_state) { + asd = spi->controller_state; + if (!asd) { + asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL); + if (!asd) + return -ENOMEM; + ret = gpio_request(npcs_pin, spi->dev.bus_id); - if (ret) + if (ret) { + kfree(asd); return ret; - spi->controller_state = (void *)npcs_pin; + } + + asd->npcs_pin = npcs_pin; + spi->controller_state = asd; gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); } else { unsigned long flags; @@ -605,11 +646,14 @@ static int atmel_spi_setup(struct spi_device *spi) spin_unlock_irqrestore(&as->lock, flags); } + asd->csr = csr; + dev_dbg(&spi->dev, "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", bus_hz / scbr, bits, spi->mode, spi->chip_select, csr); - spi_writel(as, CSR0 + 4 * spi->chip_select, csr); + if (!atmel_spi_is_v2()) + spi_writel(as, CSR0 + 4 * spi->chip_select, csr); return 0; } @@ -684,10 +728,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) static void atmel_spi_cleanup(struct spi_device *spi) { struct atmel_spi *as = spi_master_get_devdata(spi->master); + struct atmel_spi_device *asd = spi->controller_state; unsigned gpio = (unsigned) spi->controller_data; unsigned long flags; - if (!spi->controller_state) + if (!asd) return; spin_lock_irqsave(&as->lock, flags); @@ -697,7 +742,9 @@ static void atmel_spi_cleanup(struct spi_device *spi) } spin_unlock_irqrestore(&as->lock, flags); + spi->controller_state = NULL; gpio_free(gpio); + kfree(asd); } /*-------------------------------------------------------------------------*/ @@ -755,8 +802,6 @@ static int __init atmel_spi_probe(struct platform_device *pdev) goto out_free_buffer; as->irq = irq; as->clk = clk; - if (!cpu_is_at91rm9200()) - as->new_1 = 1; ret = request_irq(irq, atmel_spi_interrupt, 0, pdev->dev.bus_id, master); diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 6104f461a3cd..d0fc4ca2f656 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1561,11 +1561,12 @@ out_error_master_alloc: static int pxa2xx_spi_remove(struct platform_device *pdev) { struct driver_data *drv_data = platform_get_drvdata(pdev); - struct ssp_device *ssp = drv_data->ssp; + struct ssp_device *ssp; int status = 0; if (!drv_data) return 0; + ssp = drv_data->ssp; /* Remove the queue */ status = destroy_queue(drv_data); diff --git a/drivers/spi/spi_gpio.c b/drivers/spi/spi_gpio.c new file mode 100644 index 000000000000..49698cabc30d --- /dev/null +++ b/drivers/spi/spi_gpio.c @@ -0,0 +1,360 @@ +/* + * spi_gpio.c - SPI master driver using generic bitbanged GPIO + * + * Copyright (C) 2006,2008 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> +#include <linux/spi/spi_gpio.h> + + +/* + * This bitbanging SPI master driver should help make systems usable + * when a native hardware SPI engine is not available, perhaps because + * its driver isn't yet working or because the I/O pins it requires + * are used for other purposes. + * + * platform_device->driver_data ... points to spi_gpio + * + * spi->controller_state ... reserved for bitbang framework code + * spi->controller_data ... holds chipselect GPIO + * + * spi->master->dev.driver_data ... points to spi_gpio->bitbang + */ + +struct spi_gpio { + struct spi_bitbang bitbang; + struct spi_gpio_platform_data pdata; + struct platform_device *pdev; +}; + +/*----------------------------------------------------------------------*/ + +/* + * Because the overhead of going through four GPIO procedure calls + * per transferred bit can make performance a problem, this code + * is set up so that you can use it in either of two ways: + * + * - The slow generic way: set up platform_data to hold the GPIO + * numbers used for MISO/MOSI/SCK, and issue procedure calls for + * each of them. This driver can handle several such busses. + * + * - The quicker inlined way: only helps with platform GPIO code + * that inlines operations for constant GPIOs. This can give + * you tight (fast!) inner loops, but each such bus needs a + * new driver. You'll define a new C file, with Makefile and + * Kconfig support; the C code can be a total of six lines: + * + * #define DRIVER_NAME "myboard_spi2" + * #define SPI_MISO_GPIO 119 + * #define SPI_MOSI_GPIO 120 + * #define SPI_SCK_GPIO 121 + * #define SPI_N_CHIPSEL 4 + * #include "spi_gpio.c" + */ + +#ifndef DRIVER_NAME +#define DRIVER_NAME "spi_gpio" + +#define GENERIC_BITBANG /* vs tight inlines */ + +/* all functions referencing these symbols must define pdata */ +#define SPI_MISO_GPIO ((pdata)->miso) +#define SPI_MOSI_GPIO ((pdata)->mosi) +#define SPI_SCK_GPIO ((pdata)->sck) + +#define SPI_N_CHIPSEL ((pdata)->num_chipselect) + +#endif + +/*----------------------------------------------------------------------*/ + +static inline const struct spi_gpio_platform_data * __pure +spi_to_pdata(const struct spi_device *spi) +{ + const struct spi_bitbang *bang; + const struct spi_gpio *spi_gpio; + + bang = spi_master_get_devdata(spi->master); + spi_gpio = container_of(bang, struct spi_gpio, bitbang); + return &spi_gpio->pdata; +} + +/* this is #defined to avoid unused-variable warnings when inlining */ +#define pdata spi_to_pdata(spi) + +static inline void setsck(const struct spi_device *spi, int is_on) +{ + gpio_set_value(SPI_SCK_GPIO, is_on); +} + +static inline void setmosi(const struct spi_device *spi, int is_on) +{ + gpio_set_value(SPI_MOSI_GPIO, is_on); +} + +static inline int getmiso(const struct spi_device *spi) +{ + return gpio_get_value(SPI_MISO_GPIO); +} + +#undef pdata + +/* + * NOTE: this clocks "as fast as we can". It "should" be a function of the + * requested device clock. Software overhead means we usually have trouble + * reaching even one Mbit/sec (except when we can inline bitops), so for now + * we'll just assume we never need additional per-bit slowdowns. + */ +#define spidelay(nsecs) do {} while (0) + +#define EXPAND_BITBANG_TXRX +#include <linux/spi/spi_bitbang.h> + +/* + * These functions can leverage inline expansion of GPIO calls to shrink + * costs for a txrx bit, often by factors of around ten (by instruction + * count). That is particularly visible for larger word sizes, but helps + * even with default 8-bit words. + * + * REVISIT overheads calling these functions for each word also have + * significant performance costs. Having txrx_bufs() calls that inline + * the txrx_word() logic would help performance, e.g. on larger blocks + * used with flash storage or MMC/SD. There should also be ways to make + * GCC be less stupid about reloading registers inside the I/O loops, + * even without inlined GPIO calls; __attribute__((hot)) on GCC 4.3? + */ + +static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); +} + +static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); +} + +static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); +} + +static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); +} + +/*----------------------------------------------------------------------*/ + +static void spi_gpio_chipselect(struct spi_device *spi, int is_active) +{ + unsigned long cs = (unsigned long) spi->controller_data; + + /* set initial clock polarity */ + if (is_active) + setsck(spi, spi->mode & SPI_CPOL); + + /* SPI is normally active-low */ + gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); +} + +static int spi_gpio_setup(struct spi_device *spi) +{ + unsigned long cs = (unsigned long) spi->controller_data; + int status = 0; + + if (spi->bits_per_word > 32) + return -EINVAL; + + if (!spi->controller_state) { + status = gpio_request(cs, spi->dev.bus_id); + if (status) + return status; + status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); + } + if (!status) + status = spi_bitbang_setup(spi); + if (status) { + if (!spi->controller_state) + gpio_free(cs); + } + return status; +} + +static void spi_gpio_cleanup(struct spi_device *spi) +{ + unsigned long cs = (unsigned long) spi->controller_data; + + gpio_free(cs); + spi_bitbang_cleanup(spi); +} + +static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in) +{ + int value; + + value = gpio_request(pin, label); + if (value == 0) { + if (is_in) + value = gpio_direction_input(pin); + else + value = gpio_direction_output(pin, 0); + } + return value; +} + +static int __init +spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label) +{ + int value; + + /* NOTE: SPI_*_GPIO symbols may reference "pdata" */ + + value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false); + if (value) + goto done; + + value = spi_gpio_alloc(SPI_MISO_GPIO, label, true); + if (value) + goto free_mosi; + + value = spi_gpio_alloc(SPI_SCK_GPIO, label, false); + if (value) + goto free_miso; + + goto done; + +free_miso: + gpio_free(SPI_MISO_GPIO); +free_mosi: + gpio_free(SPI_MOSI_GPIO); +done: + return value; +} + +static int __init spi_gpio_probe(struct platform_device *pdev) +{ + int status; + struct spi_master *master; + struct spi_gpio *spi_gpio; + struct spi_gpio_platform_data *pdata; + + pdata = pdev->dev.platform_data; +#ifdef GENERIC_BITBANG + if (!pdata || !pdata->num_chipselect) + return -ENODEV; +#endif + + status = spi_gpio_request(pdata, dev_name(&pdev->dev)); + if (status < 0) + return status; + + master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio); + if (!master) { + status = -ENOMEM; + goto gpio_free; + } + spi_gpio = spi_master_get_devdata(master); + platform_set_drvdata(pdev, spi_gpio); + + spi_gpio->pdev = pdev; + if (pdata) + spi_gpio->pdata = *pdata; + + master->bus_num = pdev->id; + master->num_chipselect = SPI_N_CHIPSEL; + master->setup = spi_gpio_setup; + master->cleanup = spi_gpio_cleanup; + + spi_gpio->bitbang.master = spi_master_get(master); + spi_gpio->bitbang.chipselect = spi_gpio_chipselect; + spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; + spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; + spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; + spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3; + spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer; + spi_gpio->bitbang.flags = SPI_CS_HIGH; + + status = spi_bitbang_start(&spi_gpio->bitbang); + if (status < 0) { + spi_master_put(spi_gpio->bitbang.master); +gpio_free: + gpio_free(SPI_MISO_GPIO); + gpio_free(SPI_MOSI_GPIO); + gpio_free(SPI_SCK_GPIO); + spi_master_put(master); + } + + return status; +} + +static int __exit spi_gpio_remove(struct platform_device *pdev) +{ + struct spi_gpio *spi_gpio; + struct spi_gpio_platform_data *pdata; + int status; + + spi_gpio = platform_get_drvdata(pdev); + pdata = pdev->dev.platform_data; + + /* stop() unregisters child devices too */ + status = spi_bitbang_stop(&spi_gpio->bitbang); + spi_master_put(spi_gpio->bitbang.master); + + platform_set_drvdata(pdev, NULL); + + gpio_free(SPI_MISO_GPIO); + gpio_free(SPI_MOSI_GPIO); + gpio_free(SPI_SCK_GPIO); + + return status; +} + +MODULE_ALIAS("platform:" DRIVER_NAME); + +static struct platform_driver spi_gpio_driver = { + .driver.name = DRIVER_NAME, + .driver.owner = THIS_MODULE, + .remove = __exit_p(spi_gpio_remove), +}; + +static int __init spi_gpio_init(void) +{ + return platform_driver_probe(&spi_gpio_driver, spi_gpio_probe); +} +module_init(spi_gpio_init); + +static void __exit spi_gpio_exit(void) +{ + platform_driver_unregister(&spi_gpio_driver); +} +module_exit(spi_gpio_exit); + + +MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO "); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 256d18395a23..b3ebc1d0f85f 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -19,6 +19,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> @@ -27,7 +28,6 @@ #include <asm/dma.h> #include <mach/hardware.h> -#include <mach/regs-gpio.h> #include <plat/regs-spi.h> #include <mach/spi.h> @@ -66,7 +66,7 @@ static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol) { - s3c2410_gpio_setpin(spi->pin_cs, pol); + gpio_set_value(spi->pin_cs, pol); } static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) @@ -248,8 +248,13 @@ static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); - if (hw->pdata && hw->pdata->gpio_setup) - hw->pdata->gpio_setup(hw->pdata, 1); + if (hw->pdata) { + if (hw->set_cs == s3c24xx_spi_gpiocs) + gpio_direction_output(hw->pdata->pin_cs, 1); + + if (hw->pdata->gpio_setup) + hw->pdata->gpio_setup(hw->pdata, 1); + } } static int __init s3c24xx_spi_probe(struct platform_device *pdev) @@ -343,18 +348,27 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) goto err_no_clk; } - s3c24xx_spi_initialsetup(hw); - /* setup any gpio we can */ if (!pdata->set_cs) { - hw->set_cs = s3c24xx_spi_gpiocs; + if (pdata->pin_cs < 0) { + dev_err(&pdev->dev, "No chipselect pin\n"); + goto err_register; + } - s3c2410_gpio_setpin(pdata->pin_cs, 1); - s3c2410_gpio_cfgpin(pdata->pin_cs, S3C2410_GPIO_OUTPUT); + err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev)); + if (err) { + dev_err(&pdev->dev, "Failed to get gpio for cs\n"); + goto err_register; + } + + hw->set_cs = s3c24xx_spi_gpiocs; + gpio_direction_output(pdata->pin_cs, 1); } else hw->set_cs = pdata->set_cs; + s3c24xx_spi_initialsetup(hw); + /* register our spi controller */ err = spi_bitbang_start(&hw->bitbang); @@ -366,6 +380,9 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) return 0; err_register: + if (hw->set_cs == s3c24xx_spi_gpiocs) + gpio_free(pdata->pin_cs); + clk_disable(hw->clk); clk_put(hw->clk); @@ -401,6 +418,9 @@ static int __exit s3c24xx_spi_remove(struct platform_device *dev) free_irq(hw->irq, hw); iounmap(hw->regs); + if (hw->set_cs == s3c24xx_spi_gpiocs) + gpio_free(hw->pdata->pin_cs); + release_resource(hw->ioarea); kfree(hw->ioarea); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 243ea4ab20c8..db16112cf197 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -2051,7 +2051,7 @@ static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_ /* Virtualize mmio region */ info->fix.mmio_start = reg_addr; - par->regbase = ioremap(reg_addr, pci_resource_len(pdev, 2)); + par->regbase = pci_ioremap_bar(pdev, 2); if (!par->regbase) goto err_free_info; diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 7d1b819e501c..a9b3ada05d99 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -255,7 +255,7 @@ static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var, { if (var->bits_per_pixel != LCD_BPP) { - pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, + pr_debug("%s: depth not supported: %u BPP\n", __func__, var->bits_per_pixel); return -EINVAL; } @@ -264,7 +264,7 @@ static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var, info->var.xres_virtual != var->xres_virtual || info->var.yres_virtual != var->yres_virtual) { pr_debug("%s: Resolution not supported: X%u x Y%u \n", - __FUNCTION__, var->xres, var->yres); + __func__, var->xres, var->yres); return -EINVAL; } @@ -274,7 +274,7 @@ static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var, if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { pr_debug("%s: Memory Limit requested yres_virtual = %u\n", - __FUNCTION__, var->yres_virtual); + __func__, var->yres_virtual); return -ENOMEM; } diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index c9b191319a9a..c7ff3c1a266a 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -168,7 +168,7 @@ static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green, blue >>= 8; transp >>= 8; - ((u32 *)info->pseudo_palette)[regno] = be32_to_cpu(transp << 24 | + ((__be32 *)info->pseudo_palette)[regno] = cpu_to_be32(transp << 24 | red << 0 | green << 8 | blue << 16); return 0; } diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 39d5d643a50b..7a9e42e3a9a9 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1583,8 +1583,7 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto failed_release; cfb->dev = dev; - cfb->region = ioremap(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + cfb->region = pci_ioremap_bar(dev, 0); if (!cfb->region) goto failed_ioremap; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 3c65b0d67617..756efeb91abc 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -510,6 +510,10 @@ static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, fb_logo_ex_num = 0; for (i = 0; i < fb_logo_ex_num; i++) { + if (fb_logo_ex[i].logo->type != fb_logo.logo->type) { + fb_logo_ex[i].logo = NULL; + continue; + } height += fb_logo_ex[i].logo->height; if (height > yres) { height -= fb_logo_ex[i].logo->height; diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index f89c3cce1e0c..fe5b519860b1 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -912,6 +912,7 @@ static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { unsigned int line_length; struct gbe_timing_info timing; + int ret; /* Limit bpp to 8, 16, and 32 */ if (var->bits_per_pixel <= 8) @@ -930,8 +931,10 @@ static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->grayscale = 0; /* No grayscale for now */ - if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0) - return(-EINVAL); + ret = compute_gbe_timing(var, &timing); + var->pixclock = ret; + if (ret < 0) + return -EINVAL; /* Adjust virtual resolution, if necessary */ if (var->xres > var->xres_virtual || (!ywrap && !ypan)) diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index bb20a2289760..751e491ca8c8 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c @@ -217,8 +217,7 @@ static int __init gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *d ret = pci_request_region(dev, 0, "gx1fb (video)"); if (ret < 0) return ret; - par->vid_regs = ioremap(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + par->vid_regs = pci_ioremap_bar(dev, 0); if (!par->vid_regs) return -ENOMEM; diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index de2b8f9876a5..484118926318 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -242,23 +242,21 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de ret = pci_request_region(dev, 3, "gxfb (video processor)"); if (ret < 0) return ret; - par->vid_regs = ioremap(pci_resource_start(dev, 3), - pci_resource_len(dev, 3)); + par->vid_regs = pci_ioremap_bar(dev, 3); if (!par->vid_regs) return -ENOMEM; ret = pci_request_region(dev, 2, "gxfb (display controller)"); if (ret < 0) return ret; - par->dc_regs = ioremap(pci_resource_start(dev, 2), pci_resource_len(dev, 2)); + par->dc_regs = pci_ioremap_bar(dev, 2); if (!par->dc_regs) return -ENOMEM; ret = pci_request_region(dev, 1, "gxfb (graphics processor)"); if (ret < 0) return ret; - par->gp_regs = ioremap(pci_resource_start(dev, 1), - pci_resource_len(dev, 1)); + par->gp_regs = pci_ioremap_bar(dev, 1); if (!par->gp_regs) return -ENOMEM; diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 2cd9b74d2225..b965ecdbc604 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -379,20 +379,17 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (info->screen_base == NULL) return ret; - par->gp_regs = ioremap(pci_resource_start(dev, 1), - pci_resource_len(dev, 1)); + par->gp_regs = pci_ioremap_bar(dev, 1); if (par->gp_regs == NULL) return ret; - par->dc_regs = ioremap(pci_resource_start(dev, 2), - pci_resource_len(dev, 2)); + par->dc_regs = pci_ioremap_bar(dev, 2); if (par->dc_regs == NULL) return ret; - par->vp_regs = ioremap(pci_resource_start(dev, 3), - pci_resource_len(dev, 3)); + par->vp_regs = pci_ioremap_bar(dev, 3); if (par->vp_regs == NULL) return ret; diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index 564557792bed..896e53dea906 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -648,7 +648,7 @@ static int __devinit gxt4500_probe(struct pci_dev *pdev, info->pseudo_palette = par->pseudo_palette; info->fix.mmio_start = reg_phys; - par->regs = ioremap(reg_phys, pci_resource_len(pdev, 0)); + par->regs = pci_ioremap_bar(pdev, 0); if (!par->regs) { dev_err(&pdev->dev, "gxt4500: cannot map registers\n"); goto err_free_all; @@ -656,7 +656,7 @@ static int __devinit gxt4500_probe(struct pci_dev *pdev, info->fix.smem_start = fb_phys; info->fix.smem_len = pci_resource_len(pdev, 1); - info->screen_base = ioremap(fb_phys, pci_resource_len(pdev, 1)); + info->screen_base = pci_ioremap_bar(pdev, 1); if (!info->screen_base) { dev_err(&pdev->dev, "gxt4500: cannot map framebuffer\n"); goto err_unmap_regs; diff --git a/drivers/video/i810/i810_accel.c b/drivers/video/i810/i810_accel.c index 76764ea3486a..f5bedee4310a 100644 --- a/drivers/video/i810/i810_accel.c +++ b/drivers/video/i810/i810_accel.c @@ -301,8 +301,10 @@ void i810fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) u32 dx, dy, width, height, dest, rop = 0, color = 0; if (!info->var.accel_flags || par->dev_flags & LOCKUP || - par->depth == 4) - return cfb_fillrect(info, rect); + par->depth == 4) { + cfb_fillrect(info, rect); + return; + } if (par->depth == 1) color = rect->color; @@ -327,8 +329,10 @@ void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir; if (!info->var.accel_flags || par->dev_flags & LOCKUP || - par->depth == 4) - return cfb_copyarea(info, region); + par->depth == 4) { + cfb_copyarea(info, region); + return; + } dx = region->dx * par->depth; sx = region->sx * par->depth; @@ -366,8 +370,10 @@ void i810fb_imageblit(struct fb_info *info, const struct fb_image *image) u32 fg = 0, bg = 0, size, dst; if (!info->var.accel_flags || par->dev_flags & LOCKUP || - par->depth == 4 || image->depth != 1) - return cfb_imageblit(info, image); + par->depth == 4 || image->depth != 1) { + cfb_imageblit(info, image); + return; + } switch (info->var.bits_per_pixel) { case 8: diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index a09e23649357..6d8e5415c809 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1493,8 +1493,10 @@ static void intelfb_fillrect (struct fb_info *info, DBG_MSG("intelfb_fillrect\n"); #endif - if (!ACCEL(dinfo, info) || dinfo->depth == 4) - return cfb_fillrect(info, rect); + if (!ACCEL(dinfo, info) || dinfo->depth == 4) { + cfb_fillrect(info, rect); + return; + } if (rect->rop == ROP_COPY) rop = PAT_ROP_GXCOPY; @@ -1521,8 +1523,10 @@ static void intelfb_copyarea(struct fb_info *info, DBG_MSG("intelfb_copyarea\n"); #endif - if (!ACCEL(dinfo, info) || dinfo->depth == 4) - return cfb_copyarea(info, region); + if (!ACCEL(dinfo, info) || dinfo->depth == 4) { + cfb_copyarea(info, region); + return; + } intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx, region->dy, region->width, region->height, @@ -1540,8 +1544,10 @@ static void intelfb_imageblit(struct fb_info *info, #endif if (!ACCEL(dinfo, info) || dinfo->depth == 4 - || image->depth != 1) - return cfb_imageblit(info, image); + || image->depth != 1) { + cfb_imageblit(info, image); + return; + } if (dinfo->depth != 8) { fgcolor = dinfo->pseudo_palette[image->fg_color]; @@ -1554,8 +1560,10 @@ static void intelfb_imageblit(struct fb_info *info, if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width, image->height, image->data, image->dx, image->dy, - dinfo->pitch, info->var.bits_per_pixel)) - return cfb_imageblit(info, image); + dinfo->pitch, info->var.bits_per_pixel)) { + cfb_imageblit(info, image); + return; + } } static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index d3c3af53a290..16186240c5f2 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -329,7 +329,7 @@ const struct fb_videomode vesa_modes[] = { FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 17 1152x864-75 VESA */ - { NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3, + { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 18 1280x960-60 VESA */ diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index bfb802d26d5a..588527a254c2 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -1453,7 +1453,8 @@ neo2200_imageblit(struct fb_info *info, const struct fb_image *image) * is less than 16 bits wide. This is due to insufficient * padding when writing the image. We need to adjust * struct fb_pixmap. Not yet done. */ - return cfb_imageblit(info, image); + cfb_imageblit(info, image); + return; } bltCntl_flags = NEO_BC0_SRC_MONO; } else if (image->depth == info->var.bits_per_pixel) { @@ -1461,7 +1462,8 @@ neo2200_imageblit(struct fb_info *info, const struct fb_image *image) } else { /* We don't currently support hardware acceleration if image * depth is different from display */ - return cfb_imageblit(info, image); + cfb_imageblit(info, image); + return; } switch (info->var.bits_per_pixel) { diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c index fa4821c5572b..ad6472a894ea 100644 --- a/drivers/video/nvidia/nv_accel.c +++ b/drivers/video/nvidia/nv_accel.c @@ -300,8 +300,10 @@ void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region) if (info->state != FBINFO_STATE_RUNNING) return; - if (par->lockup) - return cfb_copyarea(info, region); + if (par->lockup) { + cfb_copyarea(info, region); + return; + } NVDmaStart(info, par, BLIT_POINT_SRC, 3); NVDmaNext(par, (region->sy << 16) | region->sx); @@ -319,8 +321,10 @@ void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) if (info->state != FBINFO_STATE_RUNNING) return; - if (par->lockup) - return cfb_fillrect(info, rect); + if (par->lockup) { + cfb_fillrect(info, rect); + return; + } if (info->var.bits_per_pixel == 8) color = rect->color; diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 68089d1456c2..6666f45a2f8c 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -539,8 +539,10 @@ static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) bgx = par->palette[image->bg_color]; break; } - if (image->depth != 1) - return cfb_imageblit(info, image); + if (image->depth != 1) { + cfb_imageblit(info, image); + return; + } if (info->var.bits_per_pixel == 8) { fgx |= fgx << 8; diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index f94ae84a58cd..dcd98793d568 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -159,6 +159,9 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, break; case SM501_MEMF_PANEL: + if (size > inf->fbmem_len) + return -ENOMEM; + ptr = inf->fbmem_len - size; fbi = inf->fb[HEAD_CRT]; @@ -172,9 +175,6 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, if (fbi && ptr < fbi->fix.smem_len) return -ENOMEM; - if (ptr < 0) - return -ENOMEM; - break; case SM501_MEMF_CRT: diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index e21fe5b6f9ff..37b433a08ce8 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -870,8 +870,10 @@ static void viafb_fillrect(struct fb_info *info, u32 col = 0, rop = 0; int pitch; - if (!viafb_accel) - return cfb_fillrect(info, rect); + if (!viafb_accel) { + cfb_fillrect(info, rect); + return; + } if (!rect->width || !rect->height) return; @@ -937,8 +939,10 @@ static void viafb_copyarea(struct fb_info *info, DEBUG_MSG(KERN_INFO "viafb_copyarea!!\n"); - if (!viafb_accel) - return cfb_copyarea(info, area); + if (!viafb_accel) { + cfb_copyarea(info, area); + return; + } if (!area->width || !area->height) return; @@ -994,8 +998,10 @@ static void viafb_imageblit(struct fb_info *info, int i; int pitch; - if (!viafb_accel) - return cfb_imageblit(info, image); + if (!viafb_accel) { + cfb_imageblit(info, image); + return; + } udata = (u32 *) image->data; |