diff options
Diffstat (limited to 'drivers/net/ethernet/i825xx/lasi_82596.c')
-rw-r--r-- | drivers/net/ethernet/i825xx/lasi_82596.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/drivers/net/ethernet/i825xx/lasi_82596.c b/drivers/net/ethernet/i825xx/lasi_82596.c new file mode 100644 index 000000000000..6eba352c52e0 --- /dev/null +++ b/drivers/net/ethernet/i825xx/lasi_82596.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /* lasi_82596.c -- driver for the intel 82596 ethernet controller, as | ||
2 | munged into HPPA boxen . | ||
3 | |||
4 | This driver is based upon 82596.c, original credits are below... | ||
5 | but there were too many hoops which HP wants jumped through to | ||
6 | keep this code in there in a sane manner. | ||
7 | |||
8 | 3 primary sources of the mess -- | ||
9 | 1) hppa needs *lots* of cacheline flushing to keep this kind of | ||
10 | MMIO running. | ||
11 | |||
12 | 2) The 82596 needs to see all of its pointers as their physical | ||
13 | address. Thus virt_to_bus/bus_to_virt are *everywhere*. | ||
14 | |||
15 | 3) The implementation HP is using seems to be significantly pickier | ||
16 | about when and how the command and RX units are started. some | ||
17 | command ordering was changed. | ||
18 | |||
19 | Examination of the mach driver leads one to believe that there | ||
20 | might be a saner way to pull this off... anyone who feels like a | ||
21 | full rewrite can be my guest. | ||
22 | |||
23 | Split 02/13/2000 Sam Creasey (sammy@oh.verio.com) | ||
24 | |||
25 | 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de) | ||
26 | 03/02/2000 changes for better/correct(?) cache-flushing (deller) | ||
27 | */ | ||
28 | |||
29 | /* 82596.c: A generic 82596 ethernet driver for linux. */ | ||
30 | /* | ||
31 | Based on Apricot.c | ||
32 | Written 1994 by Mark Evans. | ||
33 | This driver is for the Apricot 82596 bus-master interface | ||
34 | |||
35 | Modularised 12/94 Mark Evans | ||
36 | |||
37 | |||
38 | Modified to support the 82596 ethernet chips on 680x0 VME boards. | ||
39 | by Richard Hirst <richard@sleepie.demon.co.uk> | ||
40 | Renamed to be 82596.c | ||
41 | |||
42 | 980825: Changed to receive directly in to sk_buffs which are | ||
43 | allocated at open() time. Eliminates copy on incoming frames | ||
44 | (small ones are still copied). Shared data now held in a | ||
45 | non-cached page, so we can run on 68060 in copyback mode. | ||
46 | |||
47 | TBD: | ||
48 | * look at deferring rx frames rather than discarding (as per tulip) | ||
49 | * handle tx ring full as per tulip | ||
50 | * performance test to tune rx_copybreak | ||
51 | |||
52 | Most of my modifications relate to the braindead big-endian | ||
53 | implementation by Intel. When the i596 is operating in | ||
54 | 'big-endian' mode, it thinks a 32 bit value of 0x12345678 | ||
55 | should be stored as 0x56781234. This is a real pain, when | ||
56 | you have linked lists which are shared by the 680x0 and the | ||
57 | i596. | ||
58 | |||
59 | Driver skeleton | ||
60 | Written 1993 by Donald Becker. | ||
61 | Copyright 1993 United States Government as represented by the Director, | ||
62 | National Security Agency. This software may only be used and distributed | ||
63 | according to the terms of the GNU General Public License as modified by SRC, | ||
64 | incorporated herein by reference. | ||
65 | |||
66 | The author may be reached as becker@scyld.com, or C/O | ||
67 | Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 | ||
68 | |||
69 | */ | ||
70 | |||
71 | #include <linux/module.h> | ||
72 | #include <linux/kernel.h> | ||
73 | #include <linux/string.h> | ||
74 | #include <linux/ptrace.h> | ||
75 | #include <linux/errno.h> | ||
76 | #include <linux/ioport.h> | ||
77 | #include <linux/interrupt.h> | ||
78 | #include <linux/delay.h> | ||
79 | #include <linux/netdevice.h> | ||
80 | #include <linux/etherdevice.h> | ||
81 | #include <linux/skbuff.h> | ||
82 | #include <linux/init.h> | ||
83 | #include <linux/types.h> | ||
84 | #include <linux/bitops.h> | ||
85 | #include <linux/dma-mapping.h> | ||
86 | |||
87 | #include <asm/io.h> | ||
88 | #include <asm/irq.h> | ||
89 | #include <asm/pdc.h> | ||
90 | #include <asm/parisc-device.h> | ||
91 | |||
92 | #define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30" | ||
93 | |||
94 | #define PA_I82596_RESET 0 /* Offsets relative to LASI-LAN-Addr.*/ | ||
95 | #define PA_CPU_PORT_L_ACCESS 4 | ||
96 | #define PA_CHANNEL_ATTENTION 8 | ||
97 | |||
98 | #define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */ | ||
99 | |||
100 | #define DMA_ALLOC dma_alloc_noncoherent | ||
101 | #define DMA_FREE dma_free_noncoherent | ||
102 | #define DMA_WBACK(ndev, addr, len) \ | ||
103 | do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0) | ||
104 | |||
105 | #define DMA_INV(ndev, addr, len) \ | ||
106 | do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0) | ||
107 | |||
108 | #define DMA_WBACK_INV(ndev, addr, len) \ | ||
109 | do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0) | ||
110 | |||
111 | #define SYSBUS 0x0000006c; | ||
112 | |||
113 | /* big endian CPU, 82596 "big" endian mode */ | ||
114 | #define SWAP32(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) | ||
115 | #define SWAP16(x) (x) | ||
116 | |||
117 | #include "lib82596.c" | ||
118 | |||
119 | MODULE_AUTHOR("Richard Hirst"); | ||
120 | MODULE_DESCRIPTION("i82596 driver"); | ||
121 | MODULE_LICENSE("GPL"); | ||
122 | module_param(i596_debug, int, 0); | ||
123 | MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask"); | ||
124 | |||
125 | static inline void ca(struct net_device *dev) | ||
126 | { | ||
127 | gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION); | ||
128 | } | ||
129 | |||
130 | |||
131 | static void mpu_port(struct net_device *dev, int c, dma_addr_t x) | ||
132 | { | ||
133 | struct i596_private *lp = netdev_priv(dev); | ||
134 | |||
135 | u32 v = (u32) (c) | (u32) (x); | ||
136 | u16 a, b; | ||
137 | |||
138 | if (lp->options & OPT_SWAP_PORT) { | ||
139 | a = v >> 16; | ||
140 | b = v & 0xffff; | ||
141 | } else { | ||
142 | a = v & 0xffff; | ||
143 | b = v >> 16; | ||
144 | } | ||
145 | |||
146 | gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS); | ||
147 | udelay(1); | ||
148 | gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS); | ||
149 | } | ||
150 | |||
151 | #define LAN_PROM_ADDR 0xF0810000 | ||
152 | |||
153 | static int __devinit | ||
154 | lan_init_chip(struct parisc_device *dev) | ||
155 | { | ||
156 | struct net_device *netdevice; | ||
157 | struct i596_private *lp; | ||
158 | int retval; | ||
159 | int i; | ||
160 | |||
161 | if (!dev->irq) { | ||
162 | printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n", | ||
163 | __FILE__, (unsigned long)dev->hpa.start); | ||
164 | return -ENODEV; | ||
165 | } | ||
166 | |||
167 | printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", | ||
168 | (unsigned long)dev->hpa.start, dev->irq); | ||
169 | |||
170 | netdevice = alloc_etherdev(sizeof(struct i596_private)); | ||
171 | if (!netdevice) | ||
172 | return -ENOMEM; | ||
173 | SET_NETDEV_DEV(netdevice, &dev->dev); | ||
174 | parisc_set_drvdata (dev, netdevice); | ||
175 | |||
176 | netdevice->base_addr = dev->hpa.start; | ||
177 | netdevice->irq = dev->irq; | ||
178 | |||
179 | if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) { | ||
180 | for (i = 0; i < 6; i++) { | ||
181 | netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i); | ||
182 | } | ||
183 | printk(KERN_INFO | ||
184 | "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__); | ||
185 | } | ||
186 | |||
187 | lp = netdev_priv(netdevice); | ||
188 | lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0; | ||
189 | |||
190 | retval = i82596_probe(netdevice); | ||
191 | if (retval) { | ||
192 | free_netdev(netdevice); | ||
193 | return -ENODEV; | ||
194 | } | ||
195 | return retval; | ||
196 | } | ||
197 | |||
198 | static int __devexit lan_remove_chip (struct parisc_device *pdev) | ||
199 | { | ||
200 | struct net_device *dev = parisc_get_drvdata(pdev); | ||
201 | struct i596_private *lp = netdev_priv(dev); | ||
202 | |||
203 | unregister_netdev (dev); | ||
204 | DMA_FREE(&pdev->dev, sizeof(struct i596_private), | ||
205 | (void *)lp->dma, lp->dma_addr); | ||
206 | free_netdev (dev); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static struct parisc_device_id lan_tbl[] = { | ||
211 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a }, | ||
212 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 }, | ||
213 | { 0, } | ||
214 | }; | ||
215 | |||
216 | MODULE_DEVICE_TABLE(parisc, lan_tbl); | ||
217 | |||
218 | static struct parisc_driver lan_driver = { | ||
219 | .name = "lasi_82596", | ||
220 | .id_table = lan_tbl, | ||
221 | .probe = lan_init_chip, | ||
222 | .remove = __devexit_p(lan_remove_chip), | ||
223 | }; | ||
224 | |||
225 | static int __devinit lasi_82596_init(void) | ||
226 | { | ||
227 | printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n"); | ||
228 | return register_parisc_driver(&lan_driver); | ||
229 | } | ||
230 | |||
231 | module_init(lasi_82596_init); | ||
232 | |||
233 | static void __exit lasi_82596_exit(void) | ||
234 | { | ||
235 | unregister_parisc_driver(&lan_driver); | ||
236 | } | ||
237 | |||
238 | module_exit(lasi_82596_exit); | ||