From f04f0b9c3eebd01778d303481b1eb6f458d135be Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 31 Aug 2003 17:33:17 -0700 Subject: [IPV6]: linger member of ip6_flowlabel needs to be a long. --- include/net/ipv6.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8aeb974d8592..18020987d369 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -193,7 +193,7 @@ struct ip6_flowlabel struct in6_addr dst; struct ipv6_txoptions *opt; atomic_t users; - u32 linger; + unsigned long linger; u8 share; u32 owner; unsigned long lastuse; -- cgit v1.2.3 From 5bff44fc272b948a85e893a007d01b9dfb3ad04f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 1 Sep 2003 10:37:25 -0700 Subject: Be a lot more careful about TS_USEDFPU and preemption We had some races where we testecd (or set) TS_USEDFPU together with sequences that depended on the setting (like clearing or setting the TS flag in %cr0) and we could be preempted in between, which screws up the FPU state, since preemption will itself change USEDFPU and the TS flag. This makes it a lot more explicit: the "internal" low-level FPU functions ("__xxxx_fpu()") all require preemption to be disabled, and the exported "real" functions will make sure that is the case. One case - in __switch_to() - was switched to the non-preempt-safe internal version, since the scheduler itself has already disabled preemption. --- arch/i386/kernel/process.c | 2 +- arch/i386/kernel/traps.c | 3 ++- include/asm-i386/i387.h | 39 +++++++++++++++++++++++++++++---------- 3 files changed, 32 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 7f4afd0b2035..a1cb8104efb6 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -452,7 +452,7 @@ struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ - unlazy_fpu(prev_p); + __unlazy_fpu(prev_p); /* * Reload esp0, LDT and the page table pointer: diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 2edd55db64d0..a22eb78ae0b0 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -745,7 +745,8 @@ asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, * Careful.. There are problems with IBM-designed IRQ13 behaviour. * Don't touch unless you *really* know how it works. * - * Must be called with kernel preemption disabled. + * Must be called with kernel preemption disabled (in this case, + * local interrupts are disabled at the call-site in entry.S). */ asmlinkage void math_state_restore(struct pt_regs regs) { diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h index 408b16afeddc..adc63f6e7244 100644 --- a/include/asm-i386/i387.h +++ b/include/asm-i386/i387.h @@ -26,7 +26,9 @@ extern void restore_fpu( struct task_struct *tsk ); extern void kernel_fpu_begin(void); #define kernel_fpu_end() do { stts(); preempt_enable(); } while(0) - +/* + * These must be called with preempt disabled + */ static inline void __save_init_fpu( struct task_struct *tsk ) { if ( cpu_has_fxsr ) { @@ -39,19 +41,12 @@ static inline void __save_init_fpu( struct task_struct *tsk ) tsk->thread_info->status &= ~TS_USEDFPU; } -static inline void save_init_fpu( struct task_struct *tsk ) -{ - __save_init_fpu(tsk); - stts(); -} - - -#define unlazy_fpu( tsk ) do { \ +#define __unlazy_fpu( tsk ) do { \ if ((tsk)->thread_info->status & TS_USEDFPU) \ save_init_fpu( tsk ); \ } while (0) -#define clear_fpu( tsk ) \ +#define __clear_fpu( tsk ) \ do { \ if ((tsk)->thread_info->status & TS_USEDFPU) { \ asm volatile("fwait"); \ @@ -60,6 +55,30 @@ do { \ } \ } while (0) + +/* + * These disable preemption on their own and are safe + */ +static inline void save_init_fpu( struct task_struct *tsk ) +{ + preempt_disable(); + __save_init_fpu(tsk); + stts(); + preempt_enable(); +} + +#define unlazy_fpu( tsk ) do { \ + preempt_disable(); \ + __unlazy_fpu(tsk); \ + preempt_enable(); \ +} while (0) + +#define clear_fpu( tsk ) do { \ + preempt_disable(); \ + __clear_fpu( tsk ); \ + preempt_enable(); \ +} while (0) + \ /* * FPU state interaction... */ -- cgit v1.2.3 From 398bc89a69e4416cae30abcf04fb48b263eb3118 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 1 Sep 2003 14:38:35 -0700 Subject: [NET]: Use MODULE_ALIAS() in network families. Previously, default aliases were hardwired into modutils. Now they should be inside the modules, using MODULE_ALIAS() (they will be overridden by any user alias). --- include/linux/net.h | 3 +++ net/appletalk/ddp.c | 1 + net/atm/common.c | 2 ++ net/ax25/af_ax25.c | 1 + net/bluetooth/bnep/core.c | 1 + net/decnet/af_decnet.c | 1 + net/econet/af_econet.c | 1 + net/ipv4/af_inet.c | 1 + net/ipv6/af_inet6.c | 2 ++ net/ipx/af_ipx.c | 1 + net/irda/irsyms.c | 1 + net/key/af_key.c | 1 + net/llc/llc_main.c | 1 + net/netlink/af_netlink.c | 1 + net/netrom/af_netrom.c | 1 + net/packet/af_packet.c | 1 + net/rose/af_rose.c | 1 + net/unix/af_unix.c | 1 + net/wanrouter/af_wanpipe.c | 1 + net/x25/af_x25.c | 1 + 20 files changed, 24 insertions(+) (limited to 'include') diff --git a/include/linux/net.h b/include/linux/net.h index 9101b7dcec92..6f9a0992e578 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -20,6 +20,7 @@ #include #include +#include struct poll_table_struct; struct inode; @@ -243,6 +244,8 @@ static struct proto_ops name##_ops = { \ }; #endif +#define MODULE_ALIAS_NETPROTO(proto) \ + MODULE_ALIAS("net-pf-" __stringify(proto)) #endif /* __KERNEL__ */ #endif /* _LINUX_NET_H */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 95f273f16a8a..4d5469bd8140 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1940,3 +1940,4 @@ module_exit(atalk_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alan Cox "); MODULE_DESCRIPTION("AppleTalk 0.20 for Linux NET4.0\n"); +MODULE_ALIAS_NETPROTO(PF_APPLETALK); diff --git a/net/atm/common.c b/net/atm/common.c index b9a163bf9655..6fde6b018418 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -1136,3 +1136,5 @@ module_init(atm_init); module_exit(atm_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_ATMPVC); +MODULE_ALIAS_NETPROTO(PF_ATMSVC); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index d13771728f99..4bb3798a2638 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -2025,6 +2025,7 @@ module_init(ax25_init); MODULE_AUTHOR("Jonathan Naylor G4KLX "); MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_AX25); static void __exit ax25_exit(void) { diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 864e4e30d96c..4822fba968ba 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -711,3 +711,4 @@ module_exit(bnep_cleanup_module); MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION); MODULE_AUTHOR("David Libault , Maxim Krasnyanskiy "); MODULE_LICENSE("GPL"); +MODULE_ALIAS_PROTO(PF_BLUETOOTH); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 296938c8cfca..bd664d07f201 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2349,6 +2349,7 @@ void dn_unregister_sysctl(void); MODULE_DESCRIPTION("The Linux DECnet Network Protocol"); MODULE_AUTHOR("Linux DECnet Project Team"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_DECnet); static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n"; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 5425b2d31904..b84afc5a8158 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1116,3 +1116,4 @@ module_init(econet_proto_init); module_exit(econet_proto_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_ECONET); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index bb7ebed8b0de..8a5dbadd51f3 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1248,3 +1248,4 @@ int __init ipv4_proc_init(void) return 0; } #endif /* CONFIG_PROC_FS */ +MODULE_ALIAS_NETPROTO(PF_INET); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index c2df59aec2fa..6289170cb341 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -893,3 +893,5 @@ static void inet6_exit(void) } module_exit(inet6_exit); #endif /* MODULE */ + +MODULE_ALIAS_NETPROTO(PF_INET6); diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index e0a53bf2ea9e..083155a233a6 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -2021,3 +2021,4 @@ static void __exit ipx_proto_finito(void) module_init(ipx_init); module_exit(ipx_proto_finito); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_IPX); diff --git a/net/irda/irsyms.c b/net/irda/irsyms.c index 70baa3fbef5f..54def7ead679 100644 --- a/net/irda/irsyms.c +++ b/net/irda/irsyms.c @@ -351,3 +351,4 @@ MODULE_LICENSE("GPL"); #ifdef CONFIG_IRDA_DEBUG MODULE_PARM(irda_debug, "1l"); #endif +MODULE_ALIAS_NETPROTO(PF_IRDA); diff --git a/net/key/af_key.c b/net/key/af_key.c index ec9fe27e1e37..ed91a5f51335 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2844,3 +2844,4 @@ static int __init ipsec_pfkey_init(void) module_init(ipsec_pfkey_init); module_exit(ipsec_pfkey_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_KEY); diff --git a/net/llc/llc_main.c b/net/llc/llc_main.c index 63f3d5961f89..3ee7b0aa16ae 100644 --- a/net/llc/llc_main.c +++ b/net/llc/llc_main.c @@ -604,3 +604,4 @@ module_exit(llc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Procom, 1997, Arnaldo C. Melo, Jay Schullist, 2001-2003"); MODULE_DESCRIPTION("LLC 2.0, NET4.0 IEEE 802.2 extended support"); +MODULE_ALIAS_NETPROTO(PF_LLC); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8cd678de82eb..e23847781517 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1086,3 +1086,4 @@ core_initcall(netlink_proto_init); module_exit(netlink_proto_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_NETLINK); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 14be8d8dab1b..d332b90ccde6 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1460,6 +1460,7 @@ MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices"); MODULE_AUTHOR("Jonathan Naylor G4KLX "); MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_NETROM); static void __exit nr_exit(void) { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e07cba1139bb..3b593a6e17d7 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1832,3 +1832,4 @@ static int __init packet_init(void) module_init(packet_init); module_exit(packet_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_PACKET); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index c860765f12a5..69ce7b8e01da 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1551,6 +1551,7 @@ MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices"); MODULE_AUTHOR("Jonathan Naylor G4KLX "); MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_ROSE); static void __exit rose_exit(void) { diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f249d4388e36..d9dd8a2f3914 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1965,3 +1965,4 @@ module_init(af_unix_init); module_exit(af_unix_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_UNIX); diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 4f49aa6edf08..02bc8d43fe52 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -2600,3 +2600,4 @@ int init_module(void) } #endif MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_WANPIPE); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 8c5018feed69..83b57963397e 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1423,3 +1423,4 @@ module_exit(x25_exit); MODULE_AUTHOR("Jonathan Naylor "); MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_X25); -- cgit v1.2.3 From 8fc7b52843047a7d2243ab5a1a0a63516c779180 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 1 Sep 2003 17:43:31 -0700 Subject: [PATCH] ide: fix ide_unregister() vs. driver model From: Benjamin Herrenschmidt This patch seem to have been lost, so here it is again. It fixes an Ooops on unregistering hwifs due to the device model now having mandatory release() functions. It also close the possible race we had on release if the entry was in use (by or /sys typically) by using a semaphore waiting for the release() to be called after doing an unregister. --- drivers/ide/ide-probe.c | 16 ++++++++++++++++ drivers/ide/ide.c | 5 +++++ include/linux/ide.h | 3 +++ 3 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index f0c5cc5b5685..cb18ac6fa2b7 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -644,6 +644,13 @@ static inline u8 probe_for_drive (ide_drive_t *drive) return drive->present; } +static void hwif_release_dev (struct device *dev) +{ + ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev); + + up(&hwif->gendev_rel_sem); +} + static void hwif_register (ide_hwif_t *hwif) { /* register with global device tree */ @@ -656,6 +663,7 @@ static void hwif_register (ide_hwif_t *hwif) /* Would like to do = &device_legacy */ hwif->gendev.parent = NULL; } + hwif->gendev.release = hwif_release_dev; device_register(&hwif->gendev); } @@ -1196,6 +1204,13 @@ Enomem: return -ENOMEM; } +static void drive_release_dev (struct device *dev) +{ + ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); + + up(&drive->gendev_rel_sem); +} + /* * init_gendisk() (as opposed to ide_geninit) is called for each major device, * after probing for drives, to allocate partition tables and other data @@ -1214,6 +1229,7 @@ static void init_gendisk (ide_hwif_t *hwif) drive->gendev.parent = &hwif->gendev; drive->gendev.bus = &ide_bus_type; drive->gendev.driver_data = drive; + drive->gendev.release = drive_release_dev; if (drive->present) { device_register(&drive->gendev); sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d", diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 387503fa87df..8ff22ad3f648 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -251,6 +251,8 @@ static void init_hwif_data (unsigned int index) hwif->mwdma_mask = 0x80; /* disable all mwdma */ hwif->swdma_mask = 0x80; /* disable all swdma */ + sema_init(&hwif->gendev_rel_sem, 0); + default_hwif_iops(hwif); default_hwif_transport(hwif); for (unit = 0; unit < MAX_DRIVES; ++unit) { @@ -273,6 +275,7 @@ static void init_hwif_data (unsigned int index) drive->driver = &idedefault_driver; drive->vdma = 0; INIT_LIST_HEAD(&drive->list); + sema_init(&drive->gendev_rel_sem, 0); } } @@ -745,6 +748,7 @@ void ide_unregister (unsigned int index) spin_unlock_irq(&ide_lock); blk_cleanup_queue(drive->queue); device_unregister(&drive->gendev); + down(&drive->gendev_rel_sem); spin_lock_irq(&ide_lock); drive->queue = NULL; } @@ -774,6 +778,7 @@ void ide_unregister (unsigned int index) /* More messed up locking ... */ spin_unlock_irq(&ide_lock); device_unregister(&hwif->gendev); + down(&hwif->gendev_rel_sem); /* * Remove us from the kernel's knowledge diff --git a/include/linux/ide.h b/include/linux/ide.h index 98a1a968ad93..4664fd44a986 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -22,6 +22,7 @@ #include #include #include +#include #define DEBUG_PM @@ -774,6 +775,7 @@ typedef struct ide_drive_s { int crc_count; /* crc counter to reduce drive speed */ struct list_head list; struct device gendev; + struct semaphore gendev_rel_sem; /* to deal with device release() */ struct gendisk *disk; } ide_drive_t; @@ -1040,6 +1042,7 @@ typedef struct hwif_s { unsigned auto_poll : 1; /* supports nop auto-poll */ struct device gendev; + struct semaphore gendev_rel_sem; /* To deal with device release() */ void *hwif_data; /* extra hwif data */ -- cgit v1.2.3 From d964d91157abdc671d6baf4c60ac7a9f07082dc9 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 1 Sep 2003 17:43:40 -0700 Subject: [PATCH] ide: forward-port siimage driver changes from 2.4.22 ide: forward-port siimage driver changes from 2.4.22 --- drivers/ide/pci/siimage.c | 828 +++++++++++++++++++++++++++++++++------------- drivers/ide/pci/siimage.h | 25 +- include/linux/pci_ids.h | 1 + 3 files changed, 609 insertions(+), 245 deletions(-) (limited to 'include') diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 49940bf4bd94..23f0d061310d 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,7 +1,24 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.02 Jan 30, 2003 + * linux/drivers/ide/pci/siimage.c Version 1.06 June 11, 2003 * * Copyright (C) 2001-2002 Andre Hedrick + * Copyright (C) 2003 Red Hat + * + * May be copied or modified under the terms of the GNU General Public License + * + * Documentation available under NDA only + * + * + * FAQ Items: + * If you are using Marvell SATA-IDE adapters with Maxtor drives + * ensure the system is set up for ATA100/UDMA5 not UDMA6. + * + * If you are using WD drives with SATA bridges you must set the + * drive to "Single". "Master" will hang + * + * If you have strange problems with nVidia chipset systems please + * see the SI support documentation and update your system BIOS + * if neccessary */ #include @@ -22,16 +39,107 @@ #include static u8 siimage_proc = 0; -#define SIIMAGE_MAX_DEVS 5 +#define SIIMAGE_MAX_DEVS 16 static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS]; static int n_siimage_devs; -static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index) +/** + * pdev_is_sata - check if device is SATA + * @pdev: PCI device to check + * + * Returns true if this is a SATA controller + */ + +static int pdev_is_sata(struct pci_dev *pdev) +{ + switch(pdev->device) + { + case PCI_DEVICE_ID_SII_3112: + case PCI_DEVICE_ID_SII_1210SA: + return 1; + case PCI_DEVICE_ID_SII_680: + return 0; + } + BUG(); + return 0; +} + +/** + * is_sata - check if hwif is SATA + * @hwif: interface to check + * + * Returns true if this is a SATA controller + */ + +static inline int is_sata(ide_hwif_t *hwif) +{ + return pdev_is_sata(hwif->pci_dev); +} + +/** + * siimage_selreg - return register base + * @hwif: interface + * @r: config offset + * + * Turn a config register offset into the right address in either + * PCI space or MMIO space to access the control register in question + * Thankfully this is a configuration operation so isnt performance + * criticial. + */ + +static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) +{ + unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; + if(hwif->mmio) + base += (hwif->channel << 6); + else + base += (hwif->channel << 4); + return base; +} + +/** + * siimage_seldev - return register base + * @hwif: interface + * @r: config offset + * + * Turn a config register offset into the right address in either + * PCI space or MMIO space to access the control register in question + * including accounting for the unit shift. + */ + +static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; + if(hwif->mmio) + base += (hwif->channel << 6); + else + base += (hwif->channel << 4); + base |= drive->select.b.unit << drive->select.b.unit; + return base; +} + +/** + * print_siimage_get_info - print minimal proc information + * @buf: buffer to write into (kernel space) + * @dev: PCI device we are describing + * @index: Controller number + * + * Print the basic information for the state of the CMD680/SI3112 + * channel. We don't actually dump a lot of information out for + * this controller although we could expand it if we needed. + */ + +static char *print_siimage_get_info (char *buf, struct pci_dev *dev, int index) { char *p = buf; u8 mmio = (pci_get_drvdata(dev) != NULL) ? 1 : 0; - unsigned long bmdma = (mmio) ? ((unsigned long) pci_get_drvdata(dev)) : - (pci_resource_start(dev, 4)); + unsigned long bmdma = pci_resource_start(dev, 4); + + if(mmio) + bmdma = pci_resource_start(dev, 5); p += sprintf(p, "\nController: %d\n", index); p += sprintf(p, "SiI%x Chipset.\n", dev->device); @@ -39,18 +147,20 @@ static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index) p += sprintf(p, "MMIO Base 0x%lx\n", bmdma); p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma); p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8); - - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, "--------------- drive0 --------- drive1 " - "-------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "PIO Mode: %s %s" - " %s %s\n", - "?", "?", "?", "?"); return (char *)p; } +/** + * siimage_get_info - proc callback + * @buffer: kernel buffer to complete + * @addr: written with base of data to return + * offset: seek offset + * count: bytes to fill in + * + * Called when the user reads data from the virtual file for this + * controller from /proc + */ + static int siimage_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; @@ -71,46 +181,70 @@ static int siimage_get_info (char *buffer, char **addr, off_t offset, int count) #endif /* defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) */ +/** + * siimage_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. + * For the CMD680 this depends on the clocking mode (scsc), for the + * SI3312 SATA controller life is a bit simpler. Enforce UDMA33 + * as a limit if there is no 80pin cable present. + */ + static byte siimage_ratemask (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 mode = 0, scsc = 0; + unsigned long base = (unsigned long) hwif->hwif_data; if (hwif->mmio) - scsc = hwif->INB(HWIFADDR(0x4A)); + scsc = hwif->INB(base + 0x4A); else pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_SII_3112: - return 4; - case PCI_DEVICE_ID_SII_680: - if ((scsc & 0x10) == 0x10) /* 133 */ - mode = 4; - else if ((scsc & 0x30) == 0x00) /* 100 */ - mode = 3; - else if ((scsc & 0x20) == 0x20) /* 66 eek */ - BUG(); // mode = 2; - break; - default: return 0; + if(is_sata(hwif)) + { + if(strstr(drive->id->model, "Maxtor")) + return 3; + return 4; } + + if ((scsc & 0x30) == 0x10) /* 133 */ + mode = 4; + else if ((scsc & 0x30) == 0x20) /* 2xPCI */ + mode = 4; + else if ((scsc & 0x30) == 0x00) /* 100 */ + mode = 3; + else /* Disabled ? */ + BUG(); + if (!eighty_ninty_three(drive)) mode = min(mode, (u8)1); return mode; } +/** + * siimage_taskfile_timing - turn timing data to a mode + * @hwif: interface to query + * + * Read the timing data for the interface and return the + * mode that is being used. + */ + static byte siimage_taskfile_timing (ide_hwif_t *hwif) { u16 timing = 0x328a; + unsigned long addr = siimage_selreg(hwif, 2); if (hwif->mmio) - timing = hwif->INW(SELADDR(2)); + timing = hwif->INW(addr); else - pci_read_config_word(hwif->pci_dev, SELREG(2), &timing); + pci_read_config_word(hwif->pci_dev, addr, &timing); switch (timing) { case 0x10c1: return 4; case 0x10c3: return 3; + case 0x1104: case 0x1281: return 2; case 0x2283: return 1; case 0x328a: @@ -118,34 +252,88 @@ static byte siimage_taskfile_timing (ide_hwif_t *hwif) } } +/** + * simmage_tuneproc - tune a drive + * @drive: drive to tune + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller. If we are in PIO mode 3 or 4 turn on IORDY + * monitoring (bit 9). The TF timing is bits 31:16 + */ + static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u16 speedt = 0; - u8 unit = drive->select.b.unit; - - if (hwif->mmio) - speedt = hwif->INW(SELADDR(0x04|(unit<mmio) - hwif->OUTW(speedt, SELADDR(0x04|(unit<OUTW(speedt, addr); + hwif->OUTW(speedp, tfaddr); + /* Now set up IORDY */ + if(mode_wanted == 3 || mode_wanted == 4) + hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); + else + hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); + } else - pci_write_config_word(dev, SELADDR(0x04|(unit<pci_dev, addr, speedp); + pci_write_config_word(hwif->pci_dev, tfaddr, speedt); + pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp); + speedp &= ~0x200; + /* Set IORDY for mode 3 or 4 */ + if(mode_wanted == 3 || mode_wanted == 4) + speedp |= 0x200; + pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp); + } } +/** + * config_siimage_chipset_for_pio - set drive timings + * @drive: drive to tune + * @speed we want + * + * Compute the best pio mode we can for a given device. Also honour + * the timings for the driver when dealing with mixed devices. Some + * of this is ugly but its all wrapped up here + * + * The SI680 can also do VDMA - we need to start using that + * + * FIXME: we use the BIOS channel timings to avoid driving the task + * files too fast at the disk. We need to compute the master/slave + * drive PIO mode properly so that we can up the speed on a hotplug + * system. + */ + static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed) { u8 channel_timings = siimage_taskfile_timing(HWIF(drive)); @@ -166,6 +354,16 @@ static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) config_siimage_chipset_for_pio(drive, set_speed); } +/** + * siimage_tune_chipset - set controller timings + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Tune the SII chipset for the desired mode. If we can't achieve + * the desired mode then tune for a lower one, but ultimately + * make the thing work. + */ + static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) { u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; @@ -175,30 +373,32 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) ide_hwif_t *hwif = HWIF(drive); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; - u8 speed = ide_rate_filter(siimage_ratemask(drive), xferspeed); + u8 speed = ide_rate_filter(siimage_ratemask(drive), xferspeed); + unsigned long base = (unsigned long)hwif->hwif_data; u8 scsc = 0, addr_mask = ((hwif->channel) ? ((hwif->mmio) ? 0xF4 : 0x84) : ((hwif->mmio) ? 0xB4 : 0x80)); + + unsigned long ma = siimage_seldev(drive, 0x08); + unsigned long ua = siimage_seldev(drive, 0x0C); if (hwif->mmio) { - scsc = hwif->INB(HWIFADDR(0x4A)); - mode = hwif->INB(HWIFADDR(addr_mask)); - multi = hwif->INW(SELADDR(0x08|(unit<INW(SELADDR(0x0C|(unit<INB(base + 0x4A); + mode = hwif->INB(base + addr_mask); + multi = hwif->INW(ma); + ultra = hwif->INW(ua); } else { - pci_read_config_byte(hwif->pci_dev, HWIFADDR(0x8A), &scsc); + pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); - pci_read_config_word(hwif->pci_dev, - SELREG(0x08|(unit<pci_dev, - SELREG(0x0C|(unit<pci_dev, ma, &multi); + pci_read_config_word(hwif->pci_dev, ua, &ultra); } mode &= ~((unit) ? 0x30 : 0x03); ultra &= ~0x3F; scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; - scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc; + scsc = is_sata(hwif) ? 1 : scsc; switch(speed) { case XFER_PIO_4: @@ -224,8 +424,8 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) case XFER_UDMA_1: case XFER_UDMA_0: multi = dma[2]; - ultra |= ((scsc) ? (ultra5[speed - XFER_UDMA_0]) : - (ultra6[speed - XFER_UDMA_0])); + ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) : + (ultra5[speed - XFER_UDMA_0])); mode |= ((unit) ? 0x30 : 0x03); config_siimage_chipset_for_pio(drive, 0); break; @@ -234,20 +434,26 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) } if (hwif->mmio) { - hwif->OUTB(mode, HWIFADDR(addr_mask)); - hwif->OUTW(multi, SELADDR(0x08|(unit<OUTW(ultra, SELADDR(0x0C|(unit<OUTB(mode, base + addr_mask); + hwif->OUTW(multi, ma); + hwif->OUTW(ultra, ua); } else { pci_write_config_byte(hwif->pci_dev, addr_mask, mode); - pci_write_config_word(hwif->pci_dev, - SELREG(0x08|(unit<pci_dev, - SELREG(0x0C|(unit<pci_dev, ma, multi); + pci_write_config_word(hwif->pci_dev, ua, ultra); } - return (ide_config_drive_speed(drive, speed)); } +/** + * config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by the IDE layer when it wants the timings set up. + * For the CMD680 we also need to set up the PIO timings and + * enable DMA. + */ + static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, siimage_ratemask(drive)); @@ -266,14 +472,22 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ide_dma_enable(drive); } +/** + * siimage_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. If the drive isn't suitable for DMA or we hit + * other problems then we will drop down to PIO and set up + * PIO appropriately + */ + static int siimage_config_drive_for_dma (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); struct hd_driveid *id = drive->id; - if (id != NULL && (id->capability & 1) != 0 && drive->autodma) { - if (!(hwif->atapi_dma)) - goto fast_ata_pio; + if ((id->capability & 1) != 0 && drive->autodma) { /* Consult the list of known "bad" drives */ if (hwif->ide_dma_bad_drive(drive)) goto fast_ata_pio; @@ -315,18 +529,28 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 dma_altstat = 0; + unsigned long addr = siimage_selreg(hwif, 1); /* return 1 if INTR asserted */ if ((hwif->INB(hwif->dma_status) & 4) == 4) return 1; /* return 1 if Device INTR asserted */ - pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat); + pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat); if (dma_altstat & 8) return 0; //return 1; return 0; } +/** + * siimage_mmio_ide_dma_count - DMA bytes done + * @drive + * + * If we are doing VDMA the CMD680 requires a little bit + * of more careful handling and we have to read the counts + * off ourselves. For non VDMA life is normal. + */ + static int siimage_mmio_ide_dma_count (ide_drive_t *drive) { #ifdef SIIMAGE_VIRTUAL_DMAPIO @@ -334,9 +558,10 @@ static int siimage_mmio_ide_dma_count (ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); u32 count = (rq->nr_sectors * SECTOR_SIZE); u32 rcount = 0; + unsigned long addr = siimage_selreg(hwif, 0x1C); - hwif->OUTL(count, SELADDR(0x1C)); - rcount = hwif->INL(SELADDR(0x1C)); + hwif->OUTL(count, addr); + rcount = hwif->INL(addr); printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n", drive->name, count, rcount, rq->nr_sectors); @@ -345,13 +570,22 @@ static int siimage_mmio_ide_dma_count (ide_drive_t *drive) return __ide_dma_count(drive); } -/* returns 1 if dma irq issued, 0 otherwise */ +/** + * siimage_mmio_ide_dma_test_irq - check we caused an IRQ + * @drive: drive we are testing + * + * Check if we caused an IDE DMA interrupt. We may also have caused + * SATA status interrupts, if so we clean them up and continue. + */ + static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + unsigned long base = (unsigned long)hwif->hwif_data; + unsigned long addr = siimage_selreg(hwif, 0x1); if (SATA_ERROR_REG) { - u32 ext_stat = hwif->INL(HWIFADDR(0x10)); + u32 ext_stat = hwif->INL(base + 0x10); u8 watchdog = 0; if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { u32 sata_error = hwif->INL(SATA_ERROR_REG); @@ -378,7 +612,7 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) return 1; /* return 1 if Device INTR asserted */ - if ((hwif->INB(SELADDR(1)) & 8) == 8) + if ((hwif->INB(addr) & 8) == 8) return 0; //return 1; return 0; @@ -387,21 +621,29 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive) { int temp = __ide_dma_verbose(drive); -#if 0 - drive->using_dma = 0; -#endif return temp; } +/** + * siimage_busproc - bus isolation ioctl + * @drive: drive to isolate/restore + * @state: bus state to set + * + * Used by the SII3112 to handle bus isolation. As this is a + * SATA controller the work required is quite limited, we + * just have to clean up the statistics + */ + static int siimage_busproc (ide_drive_t * drive, int state) { ide_hwif_t *hwif = HWIF(drive); u32 stat_config = 0; + unsigned long addr = siimage_selreg(hwif, 0); if (hwif->mmio) { - stat_config = hwif->INL(SELADDR(0)); + stat_config = hwif->INL(addr); } else - pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config); + pci_read_config_dword(hwif->pci_dev, addr, &stat_config); switch (state) { case BUSSTATE_ON: @@ -417,12 +659,20 @@ static int siimage_busproc (ide_drive_t * drive, int state) hwif->drives[1].failures = hwif->drives[1].max_failures + 1; break; default: - return 0; + return -EINVAL; } hwif->bus_state = state; return 0; } +/** + * siimage_reset_poll - wait for sata reset + * @drive: drive we are resetting + * + * Poll the SATA phy and see whether it has come back from the dead + * yet. + */ + static int siimage_reset_poll (ide_drive_t *drive) { if (SATA_STATUS_REG) { @@ -432,13 +682,7 @@ static int siimage_reset_poll (ide_drive_t *drive) printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", hwif->name, hwif->INL(SATA_STATUS_REG)); HWGROUP(drive)->poll_timeout = 0; -#if 0 - drive->failures++; - return ide_stopped; -#else return ide_started; -#endif - return 1; } return 0; } else { @@ -446,34 +690,53 @@ static int siimage_reset_poll (ide_drive_t *drive) } } +/** + * siimage_pre_reset - reset hook + * @drive: IDE device being reset + * + * For the SATA devices we need to handle recalibration/geometry + * differently + */ + static void siimage_pre_reset (ide_drive_t *drive) { if (drive->media != ide_disk) return; - if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) { + if (is_sata(HWIF(drive))) + { drive->special.b.set_geometry = 0; drive->special.b.recalibrate = 0; } } +/** + * siimage_reset - reset a device on an siimage controller + * @drive: drive to reset + * + * Perform a controller level reset fo the device. For + * SATA we must also check the PHY. + */ + static void siimage_reset (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 reset = 0; + unsigned long addr = siimage_selreg(hwif, 0); if (hwif->mmio) { - reset = hwif->INB(SELADDR(0)); - hwif->OUTB((reset|0x03), SELADDR(0)); + reset = hwif->INB(addr); + hwif->OUTB((reset|0x03), addr); + /* FIXME:posting */ udelay(25); - hwif->OUTB(reset, SELADDR(0)); - (void) hwif->INB(SELADDR(0)); + hwif->OUTB(reset, addr); + (void) hwif->INB(addr); } else { - pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset); - pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03); + pci_read_config_byte(hwif->pci_dev, addr, &reset); + pci_write_config_byte(hwif->pci_dev, addr, reset|0x03); udelay(25); - pci_write_config_byte(hwif->pci_dev, SELREG(0), reset); - pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset); + pci_write_config_byte(hwif->pci_dev, addr, reset); + pci_read_config_byte(hwif->pci_dev, addr, &reset); } if (SATA_STATUS_REG) { @@ -489,20 +752,28 @@ static void siimage_reset (ide_drive_t *drive) } +/** + * proc_reports_siimage - add siimage controller to proc + * @dev: PCI device + * @clocking: SCSC value + * @name: controller name + * + * Report the clocking mode of the controller and add it to + * the /proc interface layer + */ + static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name) { - if (dev->device == PCI_DEVICE_ID_SII_3112) + if(pdev_is_sata(dev)) goto sata_skip; printk(KERN_INFO "%s: BASE CLOCK ", name); - clocking &= ~0x0C; + clocking &= 0x03; switch(clocking) { case 0x03: printk("DISABLED !\n"); break; case 0x02: printk("== 2X PCI \n"); break; case 0x01: printk("== 133 \n"); break; case 0x00: printk("== 100 \n"); break; - default: - BUG(); } sata_skip: @@ -517,75 +788,108 @@ sata_skip: #endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */ } +/** + * setup_mmio_siimage - switch an SI controller into MMIO + * @dev: PCI device we are configuring + * @name: device name + * + * Attempt to put the device into mmio mode. There are some slight + * complications here with certain systems where the mmio bar isnt + * mapped so we have to be sure we can fall back to I/O. + */ + static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) { unsigned long bar5 = pci_resource_start(dev, 5); - unsigned long end5 = pci_resource_end(dev, 5); + unsigned long barsize = pci_resource_len(dev, 5); u8 tmpbyte = 0; unsigned long addr; void *ioaddr; - ioaddr = ioremap_nocache(bar5, (end5 - bar5)); + /* + * Drop back to PIO if we can't map the mmio. Some + * systems seem to get terminally confused in the PCI + * spaces. + */ + + if(!request_mem_region(bar5, barsize, name)) + { + printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n"); + return 0; + } + + ioaddr = ioremap(bar5, barsize); if (ioaddr == NULL) + { + release_mem_region(bar5, barsize); return 0; + } pci_set_master(dev); pci_set_drvdata(dev, ioaddr); addr = (unsigned long) ioaddr; - if (dev->device == PCI_DEVICE_ID_SII_3112) { - writel(0, DEVADDR(0x148)); - writel(0, DEVADDR(0x1C8)); + if (pdev_is_sata(dev)) { + writel(0, addr + 0x148); + writel(0, addr + 0x1C8); } - writeb(0, DEVADDR(0xB4)); - writeb(0, DEVADDR(0xF4)); - tmpbyte = readb(DEVADDR(0x4A)); + writeb(0, addr + 0xB4); + writeb(0, addr + 0xF4); + tmpbyte = readb(addr + 0x4A); - switch(tmpbyte) { - case 0x01: - writeb(tmpbyte|0x10, DEVADDR(0x4A)); - tmpbyte = readb(DEVADDR(0x4A)); - case 0x31: - /* if clocking is disabled */ - /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, DEVADDR(0x4A)); - tmpbyte = readb(DEVADDR(0x4A)); - case 0x11: - case 0x21: + switch(tmpbyte & 0x30) { + case 0x00: + /* In 100 MHz clocking, try and switch to 133 */ + writeb(tmpbyte|0x10, addr + 0x4A); break; - default: - tmpbyte &= ~0x30; - tmpbyte |= 0x20; - writeb(tmpbyte, DEVADDR(0x4A)); + case 0x10: + /* On 133Mhz clocking */ + break; + case 0x20: + /* On PCIx2 clocking */ + break; + case 0x30: + /* Clocking is disabled */ + /* 133 clock attempt to force it on */ + writeb(tmpbyte & ~0x20, addr + 0x4A); break; } - writeb(0x72, DEVADDR(0xA1)); - writew(0x328A, DEVADDR(0xA2)); - writel(0x62DD62DD, DEVADDR(0xA4)); - writel(0x43924392, DEVADDR(0xA8)); - writel(0x40094009, DEVADDR(0xAC)); - writeb(0x72, DEVADDR(0xE1)); - writew(0x328A, DEVADDR(0xE2)); - writel(0x62DD62DD, DEVADDR(0xE4)); - writel(0x43924392, DEVADDR(0xE8)); - writel(0x40094009, DEVADDR(0xEC)); - - if (dev->device == PCI_DEVICE_ID_SII_3112) { - writel(0xFFFF0000, DEVADDR(0x108)); - writel(0xFFFF0000, DEVADDR(0x188)); - writel(0x00680000, DEVADDR(0x148)); - writel(0x00680000, DEVADDR(0x1C8)); + writeb( 0x72, addr + 0xA1); + writew( 0x328A, addr + 0xA2); + writel(0x62DD62DD, addr + 0xA4); + writel(0x43924392, addr + 0xA8); + writel(0x40094009, addr + 0xAC); + writeb( 0x72, addr + 0xE1); + writew( 0x328A, addr + 0xE2); + writel(0x62DD62DD, addr + 0xE4); + writel(0x43924392, addr + 0xE8); + writel(0x40094009, addr + 0xEC); + + if (pdev_is_sata(dev)) { + writel(0xFFFF0000, addr + 0x108); + writel(0xFFFF0000, addr + 0x188); + writel(0x00680000, addr + 0x148); + writel(0x00680000, addr + 0x1C8); } - tmpbyte = readb(DEVADDR(0x4A)); + tmpbyte = readb(addr + 0x4A); - proc_reports_siimage(dev, (tmpbyte>>=4), name); + proc_reports_siimage(dev, (tmpbyte>>4), name); return 1; } +/** + * init_chipset_siimage - set up an SI device + * @dev: PCI device + * @name: device name + * + * Perform the initial PCI set up for this device. Attempt to switch + * to 133MHz clocking if the system isn't already set up to do it. + */ + static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name) { u32 class_rev = 0; @@ -606,139 +910,150 @@ static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char pci_write_config_byte(dev, 0x80, 0x00); pci_write_config_byte(dev, 0x84, 0x00); pci_read_config_byte(dev, 0x8A, &tmpbyte); - switch(tmpbyte) { + switch(tmpbyte & 0x30) { case 0x00: - case 0x01: /* 133 clock attempt to force it on */ pci_write_config_byte(dev, 0x8A, tmpbyte|0x10); - pci_read_config_byte(dev, 0x8A, &tmpbyte); case 0x30: - case 0x31: /* if clocking is disabled */ /* 133 clock attempt to force it on */ pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20); - pci_read_config_byte(dev, 0x8A, &tmpbyte); case 0x10: - case 0x11: - case 0x20: - case 0x21: + /* 133 already */ break; - default: - tmpbyte &= ~0x30; - tmpbyte |= 0x20; - pci_write_config_byte(dev, 0x8A, tmpbyte); + case 0x20: + /* BIOS set PCI x2 clocking */ break; } - pci_read_config_byte(dev, 0x8A, &tmpbyte); - pci_write_config_byte(dev, 0xA1, 0x72); - pci_write_config_word(dev, 0xA2, 0x328A); + pci_read_config_byte(dev, 0x8A, &tmpbyte); + + pci_write_config_byte(dev, 0xA1, 0x72); + pci_write_config_word(dev, 0xA2, 0x328A); pci_write_config_dword(dev, 0xA4, 0x62DD62DD); pci_write_config_dword(dev, 0xA8, 0x43924392); pci_write_config_dword(dev, 0xAC, 0x40094009); - pci_write_config_byte(dev, 0xB1, 0x72); - pci_write_config_word(dev, 0xB2, 0x328A); + pci_write_config_byte(dev, 0xB1, 0x72); + pci_write_config_word(dev, 0xB2, 0x328A); pci_write_config_dword(dev, 0xB4, 0x62DD62DD); pci_write_config_dword(dev, 0xB8, 0x43924392); pci_write_config_dword(dev, 0xBC, 0x40094009); - pci_read_config_byte(dev, 0x8A, &tmpbyte); - proc_reports_siimage(dev, (tmpbyte>>=4), name); + proc_reports_siimage(dev, (tmpbyte>>4), name); return 0; } +/** + * init_mmio_iops_siimage - set up the iops for MMIO + * @hwif: interface to set up + * + * The basic setup here is fairly simple, we can use standard MMIO + * operations. However we do have to set the taskfile register offsets + * by hand as there isnt a standard defined layout for them this + * time. + * + * The hardware supports buffered taskfiles and also some rather nice + * extended PRD tables. Unfortunately right now we don't. + */ + static void __init init_mmio_iops_siimage (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; - unsigned long addr = (unsigned long) pci_get_drvdata(hwif->pci_dev); + void *addr = pci_get_drvdata(dev); u8 ch = hwif->channel; -// u16 i = 0; - hw_regs_t hw; + hw_regs_t hw; + unsigned long base; + + /* + * Fill in the basic HWIF bits + */ default_hwif_mmiops(hwif); + hwif->hwif_data = addr; + + /* + * Now set up the hw. We have to do this ourselves as + * the MMIO layout isnt the same as the the standard port + * based I/O + */ + memset(&hw, 0, sizeof(hw_regs_t)); + hw.priv = addr; -#if 1 -#ifdef SIIMAGE_BUFFERED_TASKFILE - hw.io_ports[IDE_DATA_OFFSET] = DEVADDR((ch) ? 0xD0 : 0x90); - hw.io_ports[IDE_ERROR_OFFSET] = DEVADDR((ch) ? 0xD1 : 0x91); - hw.io_ports[IDE_NSECTOR_OFFSET] = DEVADDR((ch) ? 0xD2 : 0x92); - hw.io_ports[IDE_SECTOR_OFFSET] = DEVADDR((ch) ? 0xD3 : 0x93); - hw.io_ports[IDE_LCYL_OFFSET] = DEVADDR((ch) ? 0xD4 : 0x94); - hw.io_ports[IDE_HCYL_OFFSET] = DEVADDR((ch) ? 0xD5 : 0x95); - hw.io_ports[IDE_SELECT_OFFSET] = DEVADDR((ch) ? 0xD6 : 0x96); - hw.io_ports[IDE_STATUS_OFFSET] = DEVADDR((ch) ? 0xD7 : 0x97); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A); -#else /* ! SIIMAGE_BUFFERED_TASKFILE */ - hw.io_ports[IDE_DATA_OFFSET] = DEVADDR((ch) ? 0xC0 : 0x80); - hw.io_ports[IDE_ERROR_OFFSET] = DEVADDR((ch) ? 0xC1 : 0x81); - hw.io_ports[IDE_NSECTOR_OFFSET] = DEVADDR((ch) ? 0xC2 : 0x82); - hw.io_ports[IDE_SECTOR_OFFSET] = DEVADDR((ch) ? 0xC3 : 0x83); - hw.io_ports[IDE_LCYL_OFFSET] = DEVADDR((ch) ? 0xC4 : 0x84); - hw.io_ports[IDE_HCYL_OFFSET] = DEVADDR((ch) ? 0xC5 : 0x85); - hw.io_ports[IDE_SELECT_OFFSET] = DEVADDR((ch) ? 0xC6 : 0x86); - hw.io_ports[IDE_STATUS_OFFSET] = DEVADDR((ch) ? 0xC7 : 0x87); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A); -#endif /* SIIMAGE_BUFFERED_TASKFILE */ -#else -#ifdef SIIMAGE_BUFFERED_TASKFILE - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A); -#else /* ! SIIMAGE_BUFFERED_TASKFILE */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A); -#endif /* SIIMAGE_BUFFERED_TASKFILE */ -#endif - -#if 0 - printk(KERN_DEBUG "%s: ", hwif->name); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i)); - printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i)); -#endif + base = (unsigned long)addr; + if(ch) + base += 0xC0; + else + base += 0x80; + + /* + * The buffered task file doesn't have status/control + * so we can't currently use it sanely since we want to + * use LBA48 mode. + */ +// base += 0x10; +// hwif->no_lba48 = 1; + + hw.io_ports[IDE_DATA_OFFSET] = base; + hw.io_ports[IDE_ERROR_OFFSET] = base + 1; + hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2; + hw.io_ports[IDE_SECTOR_OFFSET] = base + 3; + hw.io_ports[IDE_LCYL_OFFSET] = base + 4; + hw.io_ports[IDE_HCYL_OFFSET] = base + 5; + hw.io_ports[IDE_SELECT_OFFSET] = base + 6; + hw.io_ports[IDE_STATUS_OFFSET] = base + 7; + hw.io_ports[IDE_CONTROL_OFFSET] = base + 10; hw.io_ports[IDE_IRQ_OFFSET] = 0; - if (dev->device == PCI_DEVICE_ID_SII_3112) { - hw.sata_scr[SATA_STATUS_OFFSET] = DEVADDR((ch) ? 0x184 : 0x104); - hw.sata_scr[SATA_ERROR_OFFSET] = DEVADDR((ch) ? 0x188 : 0x108); - hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100); - hw.sata_misc[SATA_MISC_OFFSET] = DEVADDR((ch) ? 0x1C0 : 0x140); - hw.sata_misc[SATA_PHY_OFFSET] = DEVADDR((ch) ? 0x1C4 : 0x144); - hw.sata_misc[SATA_IEN_OFFSET] = DEVADDR((ch) ? 0x1C8 : 0x148); + if (pdev_is_sata(dev)) { + base = (unsigned long) addr; + if(ch) + base += 0x80; + hw.sata_scr[SATA_STATUS_OFFSET] = base + 0x104; + hw.sata_scr[SATA_ERROR_OFFSET] = base + 0x108; + hw.sata_scr[SATA_CONTROL_OFFSET]= base + 0x100; + hw.sata_misc[SATA_MISC_OFFSET] = base + 0x140; + hw.sata_misc[SATA_PHY_OFFSET] = base + 0x144; + hw.sata_misc[SATA_IEN_OFFSET] = base + 0x148; } - hw.priv = (void *) addr; -// hw.priv = pci_get_drvdata(hwif->pci_dev); hw.irq = hwif->pci_dev->irq; memcpy(&hwif->hw, &hw, sizeof(hw)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); - if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) { + if (is_sata(hwif)) { memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr)); memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc)); } -#ifdef SIIMAGE_BUFFERED_TASKFILE - hwif->no_lba48 = 1; -#endif /* SIIMAGE_BUFFERED_TASKFILE */ hwif->irq = hw.irq; - hwif->hwif_data = pci_get_drvdata(hwif->pci_dev); + + base = (unsigned long) addr; #ifdef SIIMAGE_LARGE_DMA - hwif->dma_base = DEVADDR((ch) ? 0x18 : 0x10); - hwif->dma_base2 = DEVADDR((ch) ? 0x08 : 0x00); - hwif->dma_prdtable = (hwif->dma_base2 + 4); +/* Watch the brackets - even Ken and Dennis get some language design wrong */ + hwif->dma_base = base + (ch ? 0x18 : 0x10); + hwif->dma_base2 = base + (ch ? 0x08 : 0x00); + hwif->dma_prdtable = hwif->dma_base2 + 4; #else /* ! SIIMAGE_LARGE_DMA */ - hwif->dma_base = DEVADDR((ch) ? 0x08 : 0x00); - hwif->dma_base2 = DEVADDR((ch) ? 0x18 : 0x10); + hwif->dma_base = base + (ch ? 0x08 : 0x00); + hwif->dma_base2 = base + (ch ? 0x18 : 0x10); #endif /* SIIMAGE_LARGE_DMA */ - hwif->mmio = 1; + hwif->mmio = 2; } +/** + * init_iops_siimage - set up iops + * @hwif: interface to set up + * + * Do the basic setup for the SIIMAGE hardware interface + * and then do the MMIO setup if we can. This is the first + * look in we get for setting up the hwif so that we + * can get the iops right before using them. + */ + static void __init init_iops_siimage (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; @@ -746,37 +1061,60 @@ static void __init init_iops_siimage (ide_hwif_t *hwif) pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; + + hwif->hwif_data = 0; hwif->rqsize = 128; - if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev))) - hwif->rqsize = 16; + if (is_sata(hwif)) + hwif->rqsize = 15; if (pci_get_drvdata(dev) == NULL) return; init_mmio_iops_siimage(hwif); } +/** + * ata66_siimage - check for 80 pin cable + * @hwif: interface to check + * + * Check for the presence of an ATA66 capable cable on the + * interface. + */ + static unsigned int __init ata66_siimage (ide_hwif_t *hwif) { + unsigned long addr = siimage_selreg(hwif, 0); if (pci_get_drvdata(hwif->pci_dev) == NULL) { u8 ata66 = 0; - pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66); + pci_read_config_byte(hwif->pci_dev, addr, &ata66); return (ata66 & 0x01) ? 1 : 0; } - return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0; + return (hwif->INB(addr) & 0x01) ? 1 : 0; } +/** + * init_hwif_siimage - set up hwif structs + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The SIIMAGE + * requires several custom handlers so we override the default + * ide DMA handlers appropriately + */ + static void __init init_hwif_siimage (ide_hwif_t *hwif) { hwif->autodma = 0; - hwif->busproc = &siimage_busproc; + hwif->resetproc = &siimage_reset; hwif->speedproc = &siimage_tune_chipset; hwif->tuneproc = &siimage_tuneproc; hwif->reset_poll = &siimage_reset_poll; hwif->pre_reset = &siimage_pre_reset; + if(is_sata(hwif)) + hwif->busproc = &siimage_busproc; + if (!hwif->dma_base) { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; @@ -787,7 +1125,7 @@ static void __init init_hwif_siimage (ide_hwif_t *hwif) hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112) + if (!is_sata(hwif)) hwif->atapi_dma = 1; hwif->ide_dma_check = &siimage_config_drive_for_dma; @@ -801,12 +1139,26 @@ static void __init init_hwif_siimage (ide_hwif_t *hwif) } else { hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq; } - if (!noautodma) - hwif->autodma = 1; + + /* + * The BIOS often doesn't set up DMA on this controller + * so we always do it. + */ + + hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; } +/** + * init_dma_siimage - set up IDE DMA + * @hwif: interface + * @dmabase: DMA base address to use + * + * For the SI chips this requires no special set up so we can just + * let the IDE DMA core do the usual work. + */ + static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase) { ide_setup_dma(hwif, dmabase, 8); @@ -815,6 +1167,15 @@ static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase) extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *); +/** + * siimage_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an SI680 or SI3112 controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) { ide_pci_device_t *d = &siimage_chipsets[id->driver_data]; @@ -828,6 +1189,7 @@ static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_devi static struct pci_device_id siimage_pci_tbl[] = { { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, { 0, }, }; @@ -850,6 +1212,6 @@ static void siimage_ide_exit(void) module_init(siimage_ide_init); module_exit(siimage_ide_exit); -MODULE_AUTHOR("Andre Hedrick"); +MODULE_AUTHOR("Andre Hedrick, Alan Cox"); MODULE_DESCRIPTION("PCI driver module for SiI IDE"); MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/siimage.h b/drivers/ide/pci/siimage.h index 24ba8adca7a5..2f6f00fab440 100644 --- a/drivers/ide/pci/siimage.h +++ b/drivers/ide/pci/siimage.h @@ -13,12 +13,6 @@ #undef SIIMAGE_BUFFERED_TASKFILE #undef SIIMAGE_LARGE_DMA -#if 0 -typedef struct ide_io_ops_s siimage_iops { - -} -#endif - #define SII_DEBUG 0 #if SII_DEBUG @@ -27,12 +21,6 @@ typedef struct ide_io_ops_s siimage_iops { #define siiprintk(x...) #endif -#define ADJREG(B,R) ((B)|(R)|((hwif->channel)<<(4+(2*(hwif->mmio))))) -#define SELREG(R) ADJREG((0xA0),(R)) -#define SELADDR(R) ((((unsigned long)hwif->hwif_data)*(hwif->mmio))|SELREG((R))) -#define HWIFADDR(R) ((((unsigned long)hwif->hwif_data)*(hwif->mmio))|(R)) -#define DEVADDR(R) (((unsigned long) pci_get_drvdata(dev))|(R)) - #if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -85,6 +73,19 @@ static ide_pci_device_t siimage_chipsets[] __devinitdata = { .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, .extra = 0, + },{ /* 2 */ + .vendor = PCI_VENDOR_ID_CMD, + .device = PCI_DEVICE_ID_SII_1210SA, + .name = "Adaptec AAR-1210SA", + .init_chipset = init_chipset_siimage, + .init_iops = init_iops_siimage, + .init_hwif = init_hwif_siimage, + .init_dma = init_dma_siimage, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, + .bootable = ON_BOARD, + .extra = 0, },{ .vendor = 0, .device = 0, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4fc931b4e76f..6e6ff10ef587 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -878,6 +878,7 @@ #define PCI_DEVICE_ID_SII_680 0x0680 #define PCI_DEVICE_ID_SII_3112 0x3112 +#define PCI_DEVICE_ID_SII_1210SA 0x0240 #define PCI_VENDOR_ID_VISION 0x1098 #define PCI_DEVICE_ID_VISION_QD8500 0x0001 -- cgit v1.2.3