diff options
| author | Patrick Gefre <pfg@sgi.com> | 2006-01-14 16:20:40 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-14 21:25:20 -0500 |
| commit | 2d0cfb527944c2cfee2cffab14f52d483e329fcf (patch) | |
| tree | b2e3340b52d83b51674f3782a208850d53d3d24d /drivers/sn | |
| parent | 7170be5f586b59bdcdab082778a5d9203ba7b667 (diff) | |
[PATCH] Altix: ioc3 serial support
Add driver support for a 2 port PCI IOC3-based serial card on Altix boxes:
This is a re-submission. On the original submission I was asked to
organize the code so that the MIPS ioc3 ethernet and serial parts could be
used with this driver. Stanislaw Skowronek was kind enough to provide the
shim layer for this - thanks Stanislaw. This patch includes the shim layer
and the Altix PCI ioc3 serial driver. The MIPS merged ioc3 ethernet and
serial support is forthcoming.
Signed-off-by: Patrick Gefre <pfg@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/sn')
| -rw-r--r-- | drivers/sn/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/sn/Makefile | 1 | ||||
| -rw-r--r-- | drivers/sn/ioc3.c | 851 |
3 files changed, 866 insertions, 0 deletions
diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig index 13b8d249da5c..d95265b187a3 100644 --- a/drivers/sn/Kconfig +++ b/drivers/sn/Kconfig | |||
| @@ -17,4 +17,18 @@ config SGI_IOC4 | |||
| 17 | If you have an SGI Altix with an IOC4-based | 17 | If you have an SGI Altix with an IOC4-based |
| 18 | I/O controller say Y. Otherwise say N. | 18 | I/O controller say Y. Otherwise say N. |
| 19 | 19 | ||
| 20 | config SGI_IOC3 | ||
| 21 | tristate "SGI IOC3 Base IO support" | ||
| 22 | depends on (IA64_GENERIC || IA64_SGI_SN2) | ||
| 23 | default m | ||
| 24 | ---help--- | ||
| 25 | This option enables basic support for the SGI IOC3-based Base IO | ||
| 26 | controller card. This option does not enable any specific | ||
| 27 | functions on such a card, but provides necessary infrastructure | ||
| 28 | for other drivers to utilize. | ||
| 29 | |||
| 30 | If you have an SGI Altix with an IOC3-based | ||
| 31 | I/O controller or a PCI IOC3 serial card say Y. | ||
| 32 | Otherwise say N. | ||
| 33 | |||
| 20 | endmenu | 34 | endmenu |
diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile index c2a284185372..2cda011597c0 100644 --- a/drivers/sn/Makefile +++ b/drivers/sn/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | obj-$(CONFIG_SGI_IOC4) += ioc4.o | 6 | obj-$(CONFIG_SGI_IOC4) += ioc4.o |
| 7 | obj-$(CONFIG_SGI_IOC3) += ioc3.o | ||
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c new file mode 100644 index 000000000000..aaa009f4a7bf --- /dev/null +++ b/drivers/sn/ioc3.c | |||
| @@ -0,0 +1,851 @@ | |||
| 1 | /* | ||
| 2 | * SGI IOC3 master driver and IRQ demuxer | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org> | ||
| 5 | * Heavily based on similar work by: | ||
| 6 | * Brent Casavant <bcasavan@sgi.com> - IOC4 master driver | ||
| 7 | * Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/config.h> | ||
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/pci.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/spinlock.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/ioc3.h> | ||
| 18 | #include <linux/rwsem.h> | ||
| 19 | |||
| 20 | #define IOC3_PCI_SIZE 0x100000 | ||
| 21 | |||
| 22 | static LIST_HEAD(ioc3_devices); | ||
| 23 | static int ioc3_counter; | ||
| 24 | static DECLARE_RWSEM(ioc3_devices_rwsem); | ||
| 25 | |||
| 26 | static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES]; | ||
| 27 | static struct ioc3_submodule *ioc3_ethernet; | ||
| 28 | static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED; | ||
| 29 | |||
| 30 | /* NIC probing code */ | ||
| 31 | |||
| 32 | #define GPCR_MLAN_EN 0x00200000 /* enable MCR to pin 8 */ | ||
| 33 | |||
| 34 | static inline unsigned mcr_pack(unsigned pulse, unsigned sample) | ||
| 35 | { | ||
| 36 | return (pulse << 10) | (sample << 2); | ||
| 37 | } | ||
| 38 | |||
| 39 | static int nic_wait(struct ioc3_driver_data *idd) | ||
| 40 | { | ||
| 41 | volatile unsigned mcr; | ||
| 42 | |||
| 43 | do { | ||
| 44 | mcr = (volatile unsigned)idd->vma->mcr; | ||
| 45 | } while (!(mcr & 2)); | ||
| 46 | |||
| 47 | return mcr & 1; | ||
| 48 | } | ||
| 49 | |||
| 50 | static int nic_reset(struct ioc3_driver_data *idd) | ||
| 51 | { | ||
| 52 | int presence; | ||
| 53 | unsigned long flags; | ||
| 54 | |||
| 55 | local_irq_save(flags); | ||
| 56 | idd->vma->mcr = mcr_pack(500, 65); | ||
| 57 | presence = nic_wait(idd); | ||
| 58 | local_irq_restore(flags); | ||
| 59 | |||
| 60 | udelay(500); | ||
| 61 | |||
| 62 | return presence; | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline int nic_read_bit(struct ioc3_driver_data *idd) | ||
| 66 | { | ||
| 67 | int result; | ||
| 68 | unsigned long flags; | ||
| 69 | |||
| 70 | local_irq_save(flags); | ||
| 71 | idd->vma->mcr = mcr_pack(6, 13); | ||
| 72 | result = nic_wait(idd); | ||
| 73 | local_irq_restore(flags); | ||
| 74 | |||
| 75 | udelay(500); | ||
| 76 | |||
| 77 | return result; | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void nic_write_bit(struct ioc3_driver_data *idd, int bit) | ||
| 81 | { | ||
| 82 | if (bit) | ||
| 83 | idd->vma->mcr = mcr_pack(6, 110); | ||
| 84 | else | ||
| 85 | idd->vma->mcr = mcr_pack(80, 30); | ||
| 86 | |||
| 87 | nic_wait(idd); | ||
| 88 | } | ||
| 89 | |||
| 90 | static unsigned nic_read_byte(struct ioc3_driver_data *idd) | ||
| 91 | { | ||
| 92 | unsigned result = 0; | ||
| 93 | int i; | ||
| 94 | |||
| 95 | for (i = 0; i < 8; i++) | ||
| 96 | result = (result >> 1) | (nic_read_bit(idd) << 7); | ||
| 97 | |||
| 98 | return result; | ||
| 99 | } | ||
| 100 | |||
| 101 | static void nic_write_byte(struct ioc3_driver_data *idd, int byte) | ||
| 102 | { | ||
| 103 | int i, bit; | ||
| 104 | |||
| 105 | for (i = 8; i; i--) { | ||
| 106 | bit = byte & 1; | ||
| 107 | byte >>= 1; | ||
| 108 | |||
| 109 | nic_write_bit(idd, bit); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | static unsigned long | ||
| 114 | nic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr) | ||
| 115 | { | ||
| 116 | int a, b, index, disc; | ||
| 117 | |||
| 118 | nic_reset(idd); | ||
| 119 | |||
| 120 | /* Search ROM. */ | ||
| 121 | nic_write_byte(idd, 0xF0); | ||
| 122 | |||
| 123 | /* Algorithm from ``Book of iButton Standards''. */ | ||
| 124 | for (index = 0, disc = 0; index < 64; index++) { | ||
| 125 | a = nic_read_bit(idd); | ||
| 126 | b = nic_read_bit(idd); | ||
| 127 | |||
| 128 | if (a && b) { | ||
| 129 | printk(KERN_WARNING "IOC3 NIC search failed.\n"); | ||
| 130 | *last = 0; | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (!a && !b) { | ||
| 135 | if (index == *last) { | ||
| 136 | addr |= 1UL << index; | ||
| 137 | } else if (index > *last) { | ||
| 138 | addr &= ~(1UL << index); | ||
| 139 | disc = index; | ||
| 140 | } else if ((addr & (1UL << index)) == 0) | ||
| 141 | disc = index; | ||
| 142 | nic_write_bit(idd, (addr>>index)&1); | ||
| 143 | continue; | ||
| 144 | } else { | ||
| 145 | if (a) | ||
| 146 | addr |= 1UL << index; | ||
| 147 | else | ||
| 148 | addr &= ~(1UL << index); | ||
| 149 | nic_write_bit(idd, a); | ||
| 150 | continue; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | *last = disc; | ||
| 154 | return addr; | ||
| 155 | } | ||
| 156 | |||
| 157 | static void nic_addr(struct ioc3_driver_data *idd, unsigned long addr) | ||
| 158 | { | ||
| 159 | int index; | ||
| 160 | |||
| 161 | nic_reset(idd); | ||
| 162 | nic_write_byte(idd, 0xF0); | ||
| 163 | for (index = 0; index < 64; index++) { | ||
| 164 | nic_read_bit(idd); | ||
| 165 | nic_read_bit(idd); | ||
| 166 | nic_write_bit(idd, (addr>>index)&1); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | static void crc16_byte(unsigned int *crc, unsigned char db) | ||
| 171 | { | ||
| 172 | int i; | ||
