diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-08-04 03:09:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-08-04 03:09:27 -0400 |
commit | d7619fe39d9769b4d4545cc511c891deea18ae08 (patch) | |
tree | 0a902533414001075b2245825e145cc2e35ce985 /drivers/net/ariadne.c | |
parent | 9ea71503a8ed9184d2d0b8ccc4d269d05f7940ae (diff) | |
parent | ed8f37370d83e695c0a4fa5d5fc7a83ecb947526 (diff) |
Merge branch 'linus' into core/urgent
Diffstat (limited to 'drivers/net/ariadne.c')
-rw-r--r-- | drivers/net/ariadne.c | 1267 |
1 files changed, 601 insertions, 666 deletions
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index b7f45cd756a2..7ed78f402042 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c | |||
@@ -34,6 +34,9 @@ | |||
34 | * - an MC68230 Parallel Interface/Timer configured as 2 parallel ports | 34 | * - an MC68230 Parallel Interface/Timer configured as 2 parallel ports |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
38 | /*#define DEBUG*/ | ||
39 | |||
37 | #include <linux/module.h> | 40 | #include <linux/module.h> |
38 | #include <linux/stddef.h> | 41 | #include <linux/stddef.h> |
39 | #include <linux/kernel.h> | 42 | #include <linux/kernel.h> |
@@ -54,802 +57,734 @@ | |||
54 | 57 | ||
55 | #include "ariadne.h" | 58 | #include "ariadne.h" |
56 | 59 | ||
57 | |||
58 | #ifdef ARIADNE_DEBUG | 60 | #ifdef ARIADNE_DEBUG |
59 | int ariadne_debug = ARIADNE_DEBUG; | 61 | int ariadne_debug = ARIADNE_DEBUG; |
60 | #else | 62 | #else |
61 | int ariadne_debug = 1; | 63 | int ariadne_debug = 1; |
62 | #endif | 64 | #endif |
63 | 65 | ||
66 | /* Macros to Fix Endianness problems */ | ||
64 | 67 | ||
65 | /* | 68 | /* Swap the Bytes in a WORD */ |
66 | * Macros to Fix Endianness problems | 69 | #define swapw(x) (((x >> 8) & 0x00ff) | ((x << 8) & 0xff00)) |
67 | */ | 70 | /* Get the Low BYTE in a WORD */ |
68 | 71 | #define lowb(x) (x & 0xff) | |
69 | /* Swap the Bytes in a WORD */ | 72 | /* Get the Swapped High WORD in a LONG */ |
70 | #define swapw(x) (((x>>8)&0x00ff)|((x<<8)&0xff00)) | 73 | #define swhighw(x) ((((x) >> 8) & 0xff00) | (((x) >> 24) & 0x00ff)) |
71 | /* Get the Low BYTE in a WORD */ | 74 | /* Get the Swapped Low WORD in a LONG */ |
72 | #define lowb(x) (x&0xff) | 75 | #define swloww(x) ((((x) << 8) & 0xff00) | (((x) >> 8) & 0x00ff)) |
73 | /* Get the Swapped High WORD in a LONG */ | ||
74 | #define swhighw(x) ((((x)>>8)&0xff00)|(((x)>>24)&0x00ff)) | ||
75 | /* Get the Swapped Low WORD in a LONG */ | ||
76 | #define swloww(x) ((((x)<<8)&0xff00)|(((x)>>8)&0x00ff)) | ||
77 | 76 | ||
78 | 77 | /* Transmit/Receive Ring Definitions */ | |
79 | /* | ||
80 | * Transmit/Receive Ring Definitions | ||
81 | */ | ||
82 | 78 | ||
83 | #define TX_RING_SIZE 5 | 79 | #define TX_RING_SIZE 5 |
84 | #define RX_RING_SIZE 16 | 80 | #define RX_RING_SIZE 16 |
85 | 81 | ||
86 | #define PKT_BUF_SIZE 1520 | 82 | #define PKT_BUF_SIZE 1520 |
87 | 83 | ||
88 | 84 | /* Private Device Data */ | |
89 | /* | ||
90 | * Private Device Data | ||
91 | */ | ||
92 | 85 | ||
93 | struct ariadne_private { | 86 | struct ariadne_private { |
94 | volatile struct TDRE *tx_ring[TX_RING_SIZE]; | 87 | volatile struct TDRE *tx_ring[TX_RING_SIZE]; |
95 | volatile struct RDRE *rx_ring[RX_RING_SIZE]; | 88 | volatile struct RDRE *rx_ring[RX_RING_SIZE]; |
96 | volatile u_short *tx_buff[TX_RING_SIZE]; | 89 | volatile u_short *tx_buff[TX_RING_SIZE]; |
97 | volatile u_short *rx_buff[RX_RING_SIZE]; | 90 | volatile u_short *rx_buff[RX_RING_SIZE]; |
98 | int cur_tx, cur_rx; /* The next free ring entry */ | 91 | int cur_tx, cur_rx; /* The next free ring entry */ |
99 | int dirty_tx; /* The ring entries to be free()ed. */ | 92 | int dirty_tx; /* The ring entries to be free()ed */ |
100 | char tx_full; | 93 | char tx_full; |
101 | }; | 94 | }; |
102 | 95 | ||
103 | 96 | /* Structure Created in the Ariadne's RAM Buffer */ | |
104 | /* | ||
105 | * Structure Created in the Ariadne's RAM Buffer | ||
106 | */ | ||
107 | 97 | ||
108 | struct lancedata { | 98 | struct lancedata { |
109 | struct TDRE tx_ring[TX_RING_SIZE]; | 99 | struct TDRE tx_ring[TX_RING_SIZE]; |
110 | struct RDRE rx_ring[RX_RING_SIZE]; | 100 | struct RDRE rx_ring[RX_RING_SIZE]; |
111 | u_short tx_buff[TX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)]; | 101 | u_short tx_buff[TX_RING_SIZE][PKT_BUF_SIZE / sizeof(u_short)]; |
112 | u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)]; | 102 | u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE / sizeof(u_short)]; |
113 | }; | 103 | }; |
114 | 104 | ||
115 | static int ariadne_open(struct net_device *dev); | ||
116 | static void ariadne_init_ring(struct net_device *dev); | ||
117 | static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, | ||
118 | struct net_device *dev); | ||
119 | static void ariadne_tx_timeout(struct net_device *dev); | ||
120 | static int ariadne_rx(struct net_device *dev); | ||
121 | static void ariadne_reset(struct net_device *dev); | ||
122 | static irqreturn_t ariadne_interrupt(int irq, void *data); | ||
123 | static int ariadne_close(struct net_device *dev); | ||
124 | static struct net_device_stats *ariadne_get_stats(struct net_device *dev); | ||
125 | static void set_multicast_list(struct net_device *dev); | ||
126 | |||
127 | |||
128 | static void memcpyw(volatile u_short *dest, u_short *src, int len) | 105 | static void memcpyw(volatile u_short *dest, u_short *src, int len) |
129 | { | 106 | { |
130 | while (len >= 2) { | 107 | while (len >= 2) { |
131 | *(dest++) = *(src++); | 108 | *(dest++) = *(src++); |
132 | len -= 2; | 109 | len -= 2; |
133 | } | 110 | } |
134 | if (len == 1) | 111 | if (len == 1) |
135 | *dest = (*(u_char *)src)<<8; | 112 | *dest = (*(u_char *)src) << 8; |
136 | } | 113 | } |
137 | 114 | ||
115 | static void ariadne_init_ring(struct net_device *dev) | ||
116 | { | ||
117 | struct ariadne_private *priv = netdev_priv(dev); | ||
118 | volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start; | ||
119 | int i; | ||
138 | 120 | ||
139 | static int __devinit ariadne_init_one(struct zorro_dev *z, | 121 | netif_stop_queue(dev); |
140 | const struct zorro_device_id *ent); | ||
141 | static void __devexit ariadne_remove_one(struct zorro_dev *z); | ||
142 | |||
143 | |||
144 | static struct zorro_device_id ariadne_zorro_tbl[] __devinitdata = { | ||
145 | { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE }, | ||
146 | { 0 } | ||
147 | }; | ||
148 | MODULE_DEVICE_TABLE(zorro, ariadne_zorro_tbl); | ||
149 | 122 | ||
150 | static struct zorro_driver ariadne_driver = { | 123 | priv->tx_full = 0; |
151 | .name = "ariadne", | 124 | priv->cur_rx = priv->cur_tx = 0; |
152 | .id_table = ariadne_zorro_tbl, | 125 | priv->dirty_tx = 0; |
153 | .probe = ariadne_init_one, | 126 | |
154 | .remove = __devexit_p(ariadne_remove_one), | 127 | /* Set up TX Ring */ |
155 | }; | 128 | for (i = 0; i < TX_RING_SIZE; i++) { |
129 | volatile struct TDRE *t = &lancedata->tx_ring[i]; | ||
130 | t->TMD0 = swloww(ARIADNE_RAM + | ||
131 | offsetof(struct lancedata, tx_buff[i])); | ||
132 | t->TMD1 = swhighw(ARIADNE_RAM + | ||
133 | offsetof(struct lancedata, tx_buff[i])) | | ||
134 | TF_STP | TF_ENP; | ||
135 | t->TMD2 = swapw((u_short)-PKT_BUF_SIZE); | ||
136 | t->TMD3 = 0; | ||
137 | priv->tx_ring[i] = &lancedata->tx_ring[i]; | ||
138 | priv->tx_buff[i] = lancedata->tx_buff[i]; | ||
139 | netdev_dbg(dev, "TX Entry %2d at %p, Buf at %p\n", | ||
140 | i, &lancedata->tx_ring[i], lancedata->tx_buff[i]); | ||
141 | } | ||
156 | 142 | ||
157 | static const struct net_device_ops ariadne_netdev_ops = { | 143 | /* Set up RX Ring */ |
158 | .ndo_open = ariadne_open, | 144 | for (i = 0; i < RX_RING_SIZE; i++) { |
159 | .ndo_stop = ariadne_close, | 145 | volatile struct RDRE *r = &lancedata->rx_ring[i]; |
160 | .ndo_start_xmit = ariadne_start_xmit, | 146 | r->RMD0 = swloww(ARIADNE_RAM + |
161 | .ndo_tx_timeout = ariadne_tx_timeout, | 147 | offsetof(struct lancedata, rx_buff[i])); |
162 | .ndo_get_stats = ariadne_get_stats, | 148 | r->RMD1 = swhighw(ARIADNE_RAM + |
163 | .ndo_set_multicast_list = set_multicast_list, | 149 | offsetof(struct lancedata, rx_buff[i])) | |
164 | .ndo_validate_addr = eth_validate_addr, | 150 | RF_OWN; |
165 | .ndo_change_mtu = eth_change_mtu, | 151 | r->RMD2 = swapw((u_short)-PKT_BUF_SIZE); |
166 | .ndo_set_mac_address = eth_mac_addr, | 152 | r->RMD3 = 0x0000; |
167 | }; | 153 | priv->rx_ring[i] = &lancedata->rx_ring[i]; |
154 | priv->rx_buff[i] = lancedata->rx_buff[i]; | ||
155 | netdev_dbg(dev, "RX Entry %2d at %p, Buf at %p\n", | ||
156 | i, &lancedata->rx_ring[i], lancedata->rx_buff[i]); | ||
157 | } | ||
158 | } | ||
168 | 159 | ||
169 | static int __devinit ariadne_init_one(struct zorro_dev *z, | 160 | static int ariadne_rx(struct net_device *dev) |
170 | const struct zorro_device_id *ent) | ||
171 | { | 161 | { |
172 | unsigned long board = z->resource.start; | 162 | struct ariadne_private *priv = netdev_priv(dev); |
173 | unsigned long base_addr = board+ARIADNE_LANCE; | 163 | int entry = priv->cur_rx % RX_RING_SIZE; |
174 | unsigned long mem_start = board+ARIADNE_RAM; | 164 | int i; |
175 | struct resource *r1, *r2; | ||
176 | struct net_device *dev; | ||
177 | struct ariadne_private *priv; | ||
178 | int err; | ||
179 | |||
180 | r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960"); | ||
181 | if (!r1) | ||
182 | return -EBUSY; | ||
183 | r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); | ||
184 | if (!r2) { | ||
185 | release_mem_region(base_addr, sizeof(struct Am79C960)); | ||
186 | return -EBUSY; | ||
187 | } | ||
188 | |||
189 | dev = alloc_etherdev(sizeof(struct ariadne_private)); | ||
190 | if (dev == NULL) { | ||
191 | release_mem_region(base_addr, sizeof(struct Am79C960)); | ||
192 | release_mem_region(mem_start, ARIADNE_RAM_SIZE); | ||
193 | return -ENOMEM; | ||
194 | } | ||
195 | |||
196 | priv = netdev_priv(dev); | ||
197 | |||
198 | r1->name = dev->name; | ||
199 | r2->name = dev->name; | ||
200 | |||
201 | dev->dev_addr[0] = 0x00; | ||
202 | dev->dev_addr[1] = 0x60; | ||
203 | dev->dev_addr[2] = 0x30; | ||
204 | dev->dev_addr[3] = (z->rom.er_SerialNumber>>16) & 0xff; | ||
205 | dev->dev_addr[4] = (z->rom.er_SerialNumber>>8) & 0xff; | ||
206 | dev->dev_addr[5] = z->rom.er_SerialNumber & 0xff; | ||
207 | dev->base_addr = ZTWO_VADDR(base_addr); | ||
208 | dev->mem_start = ZTWO_VADDR(mem_start); | ||
209 | dev->mem_end = dev->mem_start+ARIADNE_RAM_SIZE; | ||
210 | |||
211 | dev->netdev_ops = &ariadne_netdev_ops; | ||
212 | dev->watchdog_timeo = 5*HZ; | ||
213 | |||
214 | err = register_netdev(dev); | ||
215 | if (err) { | ||
216 | release_mem_region(base_addr, sizeof(struct Am79C960)); | ||
217 | release_mem_region(mem_start, ARIADNE_RAM_SIZE); | ||
218 | free_netdev(dev); | ||
219 | return err; | ||
220 | } | ||
221 | zorro_set_drvdata(z, dev); | ||
222 | 165 | ||
223 | printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address %pM\n", | 166 | /* If we own the next entry, it's a new packet. Send it up */ |
224 | dev->name, board, dev->dev_addr); | 167 | while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) { |
168 | int status = lowb(priv->rx_ring[entry]->RMD1); | ||
169 | |||
170 | if (status != (RF_STP | RF_ENP)) { /* There was an error */ | ||
171 | /* There is a tricky error noted by | ||
172 | * John Murphy <murf@perftech.com> to Russ Nelson: | ||
173 | * Even with full-sized buffers it's possible for a | ||
174 | * jabber packet to use two buffers, with only the | ||
175 | * last correctly noting the error | ||
176 | */ | ||
177 | /* Only count a general error at the end of a packet */ | ||
178 | if (status & RF_ENP) | ||
179 | dev->stats.rx_errors++; | ||
180 | if (status & RF_FRAM) | ||
181 | dev->stats.rx_frame_errors++; | ||
182 | if (status & RF_OFLO) | ||
183 | dev->stats.rx_over_errors++; | ||
184 | if (status & RF_CRC) | ||
185 | dev->stats.rx_crc_errors++; | ||
186 | if (status & RF_BUFF) | ||
187 | dev->stats.rx_fifo_errors++; | ||
188 | priv->rx_ring[entry]->RMD1 &= 0xff00 | RF_STP | RF_ENP; | ||
189 | } else { | ||
190 | /* Malloc up new buffer, compatible with net-3 */ | ||
191 | short pkt_len = swapw(priv->rx_ring[entry]->RMD3); | ||
192 | struct sk_buff *skb; | ||
193 | |||
194 | skb = dev_alloc_skb(pkt_len + 2); | ||
195 | if (skb == NULL) { | ||
196 | netdev_warn(dev, "Memory squeeze, deferring packet\n"); | ||
197 | for (i = 0; i < RX_RING_SIZE; i++) | ||
198 | if (lowb(priv->rx_ring[(entry + i) % RX_RING_SIZE]->RMD1) & RF_OWN) | ||
199 | break; | ||
200 | |||
201 | if (i > RX_RING_SIZE - 2) { | ||
202 | dev->stats.rx_dropped++; | ||
203 | priv->rx_ring[entry]->RMD1 |= RF_OWN; | ||
204 | priv->cur_rx++; | ||
205 | } | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | |||
210 | skb_reserve(skb, 2); /* 16 byte align */ | ||
211 | skb_put(skb, pkt_len); /* Make room */ | ||
212 | skb_copy_to_linear_data(skb, | ||
213 | (const void *)priv->rx_buff[entry], | ||
214 | pkt_len); | ||
215 | skb->protocol = eth_type_trans(skb, dev); | ||
216 | netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n", | ||
217 | ((u_short *)skb->data)[6], | ||
218 | skb->data + 6, skb->data, | ||
219 | (int)skb->data, (int)skb->len); | ||
220 | |||
221 | netif_rx(skb); | ||
222 | dev->stats.rx_packets++; | ||
223 | dev->stats.rx_bytes += pkt_len; | ||
224 | } | ||
225 | 225 | ||
226 | return 0; | 226 | priv->rx_ring[entry]->RMD1 |= RF_OWN; |
227 | } | 227 | entry = (++priv->cur_rx) % RX_RING_SIZE; |
228 | } | ||
228 | 229 | ||
230 | priv->cur_rx = priv->cur_rx % RX_RING_SIZE; | ||
229 | 231 | ||
230 | static int ariadne_open(struct net_device *dev) | 232 | /* We should check that at least two ring entries are free. |
231 | { | 233 | * If not, we should free one and mark stats->rx_dropped++ |
232 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 234 | */ |
233 | u_short in; | ||
234 | u_long version; | ||
235 | int i; | ||
236 | |||
237 | /* Reset the LANCE */ | ||
238 | in = lance->Reset; | ||
239 | |||
240 | /* Stop the LANCE */ | ||
241 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
242 | lance->RDP = STOP; | ||
243 | |||
244 | /* Check the LANCE version */ | ||
245 | lance->RAP = CSR88; /* Chip ID */ | ||
246 | version = swapw(lance->RDP); | ||
247 | lance->RAP = CSR89; /* Chip ID */ | ||
248 | version |= swapw(lance->RDP)<<16; | ||
249 | if ((version & 0x00000fff) != 0x00000003) { | ||
250 | printk(KERN_WARNING "ariadne_open: Couldn't find AMD Ethernet Chip\n"); | ||
251 | return -EAGAIN; | ||
252 | } | ||
253 | if ((version & 0x0ffff000) != 0x00003000) { | ||
254 | printk(KERN_WARNING "ariadne_open: Couldn't find Am79C960 (Wrong part " | ||
255 | "number = %ld)\n", (version & 0x0ffff000)>>12); | ||
256 | return -EAGAIN; | ||
257 | } | ||
258 | #if 0 | ||
259 | printk(KERN_DEBUG "ariadne_open: Am79C960 (PCnet-ISA) Revision %ld\n", | ||
260 | (version & 0xf0000000)>>28); | ||
261 | #endif | ||
262 | 235 | ||
263 | ariadne_init_ring(dev); | 236 | return 0; |
264 | |||
265 | /* Miscellaneous Stuff */ | ||
266 | lance->RAP = CSR3; /* Interrupt Masks and Deferral Control */ | ||
267 | lance->RDP = 0x0000; | ||
268 | lance->RAP = CSR4; /* Test and Features Control */ | ||
269 | lance->RDP = DPOLL|APAD_XMT|MFCOM|RCVCCOM|TXSTRTM|JABM; | ||
270 | |||
271 | /* Set the Multicast Table */ | ||
272 | lance->RAP = CSR8; /* Logical Address Filter, LADRF[15:0] */ | ||
273 | lance->RDP = 0x0000; | ||
274 | lance->RAP = CSR9; /* Logical Address Filter, LADRF[31:16] */ | ||
275 | lance->RDP = 0x0000; | ||
276 | lance->RAP = CSR10; /* Logical Address Filter, LADRF[47:32] */ | ||
277 | lance->RDP = 0x0000; | ||
278 | lance->RAP = CSR11; /* Logical Address Filter, LADRF[63:48] */ | ||
279 | lance->RDP = 0x0000; | ||
280 | |||
281 | /* Set the Ethernet Hardware Address */ | ||
282 | lance->RAP = CSR12; /* Physical Address Register, PADR[15:0] */ | ||
283 | lance->RDP = ((u_short *)&dev->dev_addr[0])[0]; | ||
284 | lance->RAP = CSR13; /* Physical Address Register, PADR[31:16] */ | ||
285 | lance->RDP = ((u_short *)&dev->dev_addr[0])[1]; | ||
286 | lance->RAP = CSR14; /* Physical Address Register, PADR[47:32] */ | ||
287 | lance->RDP = ((u_short *)&dev->dev_addr[0])[2]; | ||
288 | |||
289 | /* Set the Init Block Mode */ | ||
290 | lance->RAP = CSR15; /* Mode Register */ | ||
291 | lance->RDP = 0x0000; | ||
292 | |||
293 | /* Set the Transmit Descriptor Ring Pointer */ | ||
294 | lance->RAP = CSR30; /* Base Address of Transmit Ring */ | ||
295 | lance->RDP = swloww(ARIADNE_RAM+offsetof(struct lancedata, tx_ring)); | ||
296 | lance->RAP = CSR31; /* Base Address of transmit Ring */ | ||
297 | lance->RDP = swhighw(ARIADNE_RAM+offsetof(struct lancedata, tx_ring)); | ||
298 | |||
299 | /* Set the Receive Descriptor Ring Pointer */ | ||
300 | lance->RAP = CSR24; /* Base Address of Receive Ring */ | ||
301 | lance->RDP = swloww(ARIADNE_RAM+offsetof(struct lancedata, rx_ring)); | ||
302 | lance->RAP = CSR25; /* Base Address of Receive Ring */ | ||
303 | lance->RDP = swhighw(ARIADNE_RAM+offsetof(struct lancedata, rx_ring)); | ||
304 | |||
305 | /* Set the Number of RX and TX Ring Entries */ | ||
306 | lance->RAP = CSR76; /* Receive Ring Length */ | ||
307 | lance->RDP = swapw(((u_short)-RX_RING_SIZE)); | ||
308 | lance->RAP = CSR78; /* Transmit Ring Length */ | ||
309 | lance->RDP = swapw(((u_short)-TX_RING_SIZE)); | ||
310 | |||
311 | /* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */ | ||
312 | lance->RAP = ISACSR2; /* Miscellaneous Configuration */ | ||
313 | lance->IDP = ASEL; | ||
314 | |||
315 | /* LED Control */ | ||
316 | lance->RAP = ISACSR5; /* LED1 Status */ | ||
317 | lance->IDP = PSE|XMTE; | ||
318 | lance->RAP = ISACSR6; /* LED2 Status */ | ||
319 | lance->IDP = PSE|COLE; | ||
320 | lance->RAP = ISACSR7; /* LED3 Status */ | ||
321 | lance->IDP = PSE|RCVE; | ||
322 | |||
323 | netif_start_queue(dev); | ||
324 | |||
325 | i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, IRQF_SHARED, | ||
326 | dev->name, dev); | ||
327 | if (i) return i; | ||
328 | |||
329 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
330 | lance->RDP = INEA|STRT; | ||
331 | |||
332 | return 0; | ||
333 | } | 237 | } |
334 | 238 | ||
335 | 239 | static irqreturn_t ariadne_interrupt(int irq, void *data) | |
336 | static void ariadne_init_ring(struct net_device *dev) | ||
337 | { | 240 | { |
338 | struct ariadne_private *priv = netdev_priv(dev); | 241 | struct net_device *dev = (struct net_device *)data; |
339 | volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start; | 242 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; |
340 | int i; | 243 | struct ariadne_private *priv; |
341 | 244 | int csr0, boguscnt; | |
342 | netif_stop_queue(dev); | 245 | int handled = 0; |
343 | 246 | ||
344 | priv->tx_full = 0; | 247 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ |
345 | priv->cur_rx = priv->cur_tx = 0; | 248 | |
346 | priv->dirty_tx = 0; | 249 | if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ |
347 | 250 | return IRQ_NONE; /* generated by the board */ | |
348 | /* Set up TX Ring */ | 251 | |
349 | for (i = 0; i < TX_RING_SIZE; i++) { | 252 | priv = netdev_priv(dev); |
350 | volatile struct TDRE *t = &lancedata->tx_ring[i]; | 253 | |
351 | t->TMD0 = swloww(ARIADNE_RAM+offsetof(struct lancedata, tx_buff[i])); | 254 | boguscnt = 10; |
352 | t->TMD1 = swhighw(ARIADNE_RAM+offsetof(struct lancedata, tx_buff[i])) | | 255 | while ((csr0 = lance->RDP) & (ERR | RINT | TINT) && --boguscnt >= 0) { |
353 | TF_STP | TF_ENP; | 256 | /* Acknowledge all of the current interrupt sources ASAP */ |
354 | t->TMD2 = swapw((u_short)-PKT_BUF_SIZE); | 257 | lance->RDP = csr0 & ~(INEA | TDMD | STOP | STRT | INIT); |
355 | t->TMD3 = 0; | 258 | |
356 | priv->tx_ring[i] = &lancedata->tx_ring[i]; | 259 | #ifdef DEBUG |
357 | priv->tx_buff[i] = lancedata->tx_buff[i]; | 260 | if (ariadne_debug > 5) { |
358 | #if 0 | 261 | netdev_dbg(dev, "interrupt csr0=%#02x new csr=%#02x [", |
359 | printk(KERN_DEBUG "TX Entry %2d at %p, Buf at %p\n", i, | 262 | csr0, lance->RDP); |
360 | &lancedata->tx_ring[i], lancedata->tx_buff[i]); | 263 | if (csr0 & INTR) |
361 | #endif | 264 | pr_cont(" INTR"); |
362 | } | 265 | if (csr0 & INEA) |
363 | 266 | pr_cont(" INEA"); | |
364 | /* Set up RX Ring */ | 267 | if (csr0 & RXON) |
365 | for (i = 0; i < RX_RING_SIZE; i++) { | 268 | pr_cont(" RXON"); |
366 | volatile struct RDRE *r = &lancedata->rx_ring[i]; | 269 | if (csr0 & TXON) |
367 | r->RMD0 = swloww(ARIADNE_RAM+offsetof(struct lancedata, rx_buff[i])); | 270 | pr_cont(" TXON"); |
368 | r->RMD1 = swhighw(ARIADNE_RAM+offsetof(struct lancedata, rx_buff[i])) | | 271 | if (csr0 & TDMD) |
369 | RF_OWN; | 272 | pr_cont(" TDMD"); |
370 | r->RMD2 = swapw((u_short)-PKT_BUF_SIZE); | 273 | if (csr0 & STOP) |
371 | r->RMD3 = 0x0000; | 274 | pr_cont(" STOP"); |
372 | priv->rx_ring[i] = &lancedata->rx_ring[i]; | 275 | if (csr0 & STRT) |
373 | priv->rx_buff[i] = lancedata->rx_buff[i]; | 276 | pr_cont(" STRT"); |
374 | #if 0 | 277 | if (csr0 & INIT) |
375 | printk(KERN_DEBUG "RX Entry %2d at %p, Buf at %p\n", i, | 278 | pr_cont(" INIT"); |
376 | &lancedata->rx_ring[i], lancedata->rx_buff[i]); | 279 | if (csr0 & ERR) |
280 | pr_cont(" ERR"); | ||
281 | if (csr0 & BABL) | ||
282 | pr_cont(" BABL"); | ||
283 | if (csr0 & CERR) | ||
284 | pr_cont(" CERR"); | ||
285 | if (csr0 & MISS) | ||
286 | pr_cont(" MISS"); | ||
287 | if (csr0 & MERR) | ||
288 | pr_cont(" MERR"); | ||
289 | if (csr0 & RINT) | ||
290 | pr_cont(" RINT"); | ||
291 | if (csr0 & TINT) | ||
292 | pr_cont(" TINT"); | ||
293 | if (csr0 & IDON) | ||
294 | pr_cont(" IDON"); | ||
295 | pr_cont(" ]\n"); | ||
296 | } | ||
377 | #endif | 297 | #endif |
378 | } | ||
379 | } | ||
380 | 298 | ||
299 | if (csr0 & RINT) { /* Rx interrupt */ | ||
300 | handled = 1; | ||
301 | ariadne_rx(dev); | ||
302 | } | ||
381 | 303 | ||
382 | static int ariadne_close(struct net_device *dev) | 304 | if (csr0 & TINT) { /* Tx-done interrupt */ |
383 | { | 305 | int dirty_tx = priv->dirty_tx; |
384 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 306 | |
307 | handled = 1; | ||
308 | while (dirty_tx < priv->cur_tx) { | ||
309 | int entry = dirty_tx % TX_RING_SIZE; | ||
310 | int status = lowb(priv->tx_ring[entry]->TMD1); | ||
311 | |||
312 | if (status & TF_OWN) | ||
313 | break; /* It still hasn't been Txed */ | ||
314 | |||
315 | priv->tx_ring[entry]->TMD1 &= 0xff00; | ||
316 | |||
317 | if (status & TF_ERR) { | ||
318 | /* There was an major error, log it */ | ||
319 | int err_status = priv->tx_ring[entry]->TMD3; | ||
320 | dev->stats.tx_errors++; | ||
321 | if (err_status & EF_RTRY) | ||
322 | dev->stats.tx_aborted_errors++; | ||
323 | if (err_status & EF_LCAR) | ||
324 | dev->stats.tx_carrier_errors++; | ||
325 | if (err_status & EF_LCOL) | ||
326 | dev->stats.tx_window_errors++; | ||
327 | if (err_status & EF_UFLO) { | ||
328 | /* Ackk! On FIFO errors the Tx unit is turned off! */ | ||
329 | dev->stats.tx_fifo_errors++; | ||
330 | /* Remove this verbosity later! */ | ||
331 | netdev_err(dev, "Tx FIFO error! Status %04x\n", | ||
332 | csr0); | ||
333 | /* Restart the chip */ | ||
334 | lance->RDP = STRT; | ||
335 | } | ||
336 | } else { | ||
337 | if (status & (TF_MORE | TF_ONE)) | ||
338 | dev->stats.collisions++; | ||
339 | dev->stats.tx_packets++; | ||
340 | } | ||
341 | dirty_tx++; | ||
342 | } | ||
385 | 343 | ||
386 | netif_stop_queue(dev); | 344 | #ifndef final_version |
345 | if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) { | ||
346 | netdev_err(dev, "out-of-sync dirty pointer, %d vs. %d, full=%d\n", | ||
347 | dirty_tx, priv->cur_tx, | ||
348 | priv->tx_full); | ||
349 | dirty_tx += TX_RING_SIZE; | ||
350 | } | ||
351 | #endif | ||
387 | 352 | ||
388 | lance->RAP = CSR112; /* Missed Frame Count */ | 353 | if (priv->tx_full && netif_queue_stopped(dev) && |
389 | dev->stats.rx_missed_errors = swapw(lance->RDP); | 354 | dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) { |
390 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | 355 | /* The ring is no longer full */ |
356 | priv->tx_full = 0; | ||
357 | netif_wake_queue(dev); | ||
358 | } | ||
391 | 359 | ||
392 | if (ariadne_debug > 1) { | 360 | priv->dirty_tx = dirty_tx; |
393 | printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", | 361 | } |
394 | dev->name, lance->RDP); | ||
395 | printk(KERN_DEBUG "%s: %lu packets missed\n", dev->name, | ||
396 | dev->stats.rx_missed_errors); | ||
397 | } | ||
398 | 362 | ||
399 | /* We stop the LANCE here -- it occasionally polls memory if we don't. */ | 363 | /* Log misc errors */ |
400 | lance->RDP = STOP; | 364 | if (csr0 & BABL) { |
365 | handled = 1; | ||
366 | dev->stats.tx_errors++; /* Tx babble */ | ||
367 | } | ||
368 | if (csr0 & MISS) { | ||
369 | handled = 1; | ||
370 | dev->stats.rx_errors++; /* Missed a Rx frame */ | ||
371 | } | ||
372 | if (csr0 & MERR) { | ||
373 | handled = 1; | ||
374 | netdev_err(dev, "Bus master arbitration failure, status %04x\n", | ||
375 | csr0); | ||
376 | /* Restart the chip */ | ||
377 | lance->RDP = STRT; | ||
378 | } | ||
379 | } | ||
401 | 380 | ||
402 | free_irq(IRQ_AMIGA_PORTS, dev); | 381 | /* Clear any other interrupt, and set interrupt enable */ |
382 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
383 | lance->RDP = INEA | BABL | CERR | MISS | MERR | IDON; | ||
403 | 384 | ||
404 | return 0; | 385 | if (ariadne_debug > 4) |
405 | } | 386 | netdev_dbg(dev, "exiting interrupt, csr%d=%#04x\n", |
387 | lance->RAP, lance->RDP); | ||
406 | 388 | ||
389 | return IRQ_RETVAL(handled); | ||
390 | } | ||
407 | 391 | ||
408 | static inline void ariadne_reset(struct net_device *dev) | 392 | static int ariadne_open(struct net_device *dev) |
409 | { | 393 | { |
410 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 394 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; |
411 | 395 | u_short in; | |
412 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | 396 | u_long version; |
413 | lance->RDP = STOP; | 397 | int i; |
414 | ariadne_init_ring(dev); | ||
415 | lance->RDP = INEA|STRT; | ||
416 | netif_start_queue(dev); | ||
417 | } | ||
418 | 398 | ||
399 | /* Reset the LANCE */ | ||
400 | in = lance->Reset; | ||
401 | |||
402 | /* Stop the LANCE */ | ||
403 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
404 | lance->RDP = STOP; | ||
405 | |||
406 | /* Check the LANCE version */ | ||
407 | lance->RAP = CSR88; /* Chip ID */ | ||
408 | version = swapw(lance->RDP); | ||
409 | lance->RAP = CSR89; /* Chip ID */ | ||
410 | version |= swapw(lance->RDP) << 16; | ||
411 | if ((version & 0x00000fff) != 0x00000003) { | ||
412 | pr_warn("Couldn't find AMD Ethernet Chip\n"); | ||
413 | return -EAGAIN; | ||
414 | } | ||
415 | if ((version & 0x0ffff000) != 0x00003000) { | ||
416 | pr_warn("Couldn't find Am79C960 (Wrong part number = %ld)\n", | ||
417 | (version & 0x0ffff000) >> 12); | ||
418 | return -EAGAIN; | ||
419 | } | ||
419 | 420 | ||
420 | static irqreturn_t ariadne_interrupt(int irq, void *data) | 421 | netdev_dbg(dev, "Am79C960 (PCnet-ISA) Revision %ld\n", |
421 | { | 422 | (version & 0xf0000000) >> 28); |
422 | struct net_device *dev = (struct net_device *)data; | ||
423 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | ||
424 | struct ariadne_private *priv; | ||
425 | int csr0, boguscnt; | ||
426 | int handled = 0; | ||
427 | 423 | ||
428 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | 424 | ariadne_init_ring(dev); |
429 | 425 | ||
430 | if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ | 426 | /* Miscellaneous Stuff */ |
431 | return IRQ_NONE; /* generated by the board. */ | 427 | lance->RAP = CSR3; /* Interrupt Masks and Deferral Control */ |
428 | lance->RDP = 0x0000; | ||
429 | lance->RAP = CSR4; /* Test and Features Control */ | ||
430 | lance->RDP = DPOLL | APAD_XMT | MFCOM | RCVCCOM | TXSTRTM | JABM; | ||
432 | 431 | ||
433 | priv = netdev_priv(dev); | 432 | /* Set the Multicast Table */ |
433 | lance->RAP = CSR8; /* Logical Address Filter, LADRF[15:0] */ | ||
434 | lance->RDP = 0x0000; | ||
435 | lance->RAP = CSR9; /* Logical Address Filter, LADRF[31:16] */ | ||
436 | lance->RDP = 0x0000; | ||
437 | lance->RAP = CSR10; /* Logical Address Filter, LADRF[47:32] */ | ||
438 | lance->RDP = 0x0000; | ||
439 | lance->RAP = CSR11; /* Logical Address Filter, LADRF[63:48] */ | ||
440 | lance->RDP = 0x0000; | ||
434 | 441 | ||
435 | boguscnt = 10; | 442 | /* Set the Ethernet Hardware Address */ |
436 | while ((csr0 = lance->RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) { | 443 | lance->RAP = CSR12; /* Physical Address Register, PADR[15:0] */ |
437 | /* Acknowledge all of the current interrupt sources ASAP. */ | 444 | lance->RDP = ((u_short *)&dev->dev_addr[0])[0]; |
438 | lance->RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT); | 445 | lance->RAP = CSR13; /* Physical Address Register, PADR[31:16] */ |
446 | lance->RDP = ((u_short *)&dev->dev_addr[0])[1]; | ||
447 | lance->RAP = CSR14; /* Physical Address Register, PADR[47:32] */ | ||
448 | lance->RDP = ((u_short *)&dev->dev_addr[0])[2]; | ||
439 | 449 | ||
440 | #if 0 | 450 | /* Set the Init Block Mode */ |
441 | if (ariadne_debug > 5) { | 451 | lance->RAP = CSR15; /* Mode Register */ |
442 | printk(KERN_DEBUG "%s: interrupt csr0=%#2.2x new csr=%#2.2x.", | 452 | lance->RDP = 0x0000; |
443 | dev->name, csr0, lance->RDP); | ||
444 | printk("["); | ||
445 | if (csr0 & INTR) | ||
446 | printk(" INTR"); | ||
447 | if (csr0 & INEA) | ||
448 | printk(" INEA"); | ||
449 | if (csr0 & RXON) | ||
450 | printk(" RXON"); | ||
451 | if (csr0 & TXON) | ||
452 | printk(" TXON"); | ||
453 | if (csr0 & TDMD) | ||
454 | printk(" TDMD"); | ||
455 | if (csr0 & STOP) | ||
456 | printk(" STOP"); | ||
457 | if (csr0 & STRT) | ||
458 | printk(" STRT"); | ||
459 | if (csr0 & INIT) | ||
460 | printk(" INIT"); | ||
461 | if (csr0 & ERR) | ||
462 | printk(" ERR"); | ||
463 | if (csr0 & BABL) | ||
464 | printk(" BABL"); | ||
465 | if (csr0 & CERR) | ||
466 | printk(" CERR"); | ||
467 | if (csr0 & MISS) | ||
468 | printk(" MISS"); | ||
469 | if (csr0 & MERR) | ||
470 | printk(" MERR"); | ||
471 | if (csr0 & RINT) | ||
472 | printk(" RINT"); | ||
473 | if (csr0 & TINT) | ||
474 | printk(" TINT"); | ||
475 | if (csr0 & IDON) | ||
476 | printk(" IDON"); | ||
477 | printk(" ]\n"); | ||
478 | } | ||
479 | #endif | ||
480 | 453 | ||
481 | if (csr0 & RINT) { /* Rx interrupt */ | 454 | /* Set the Transmit Descriptor Ring Pointer */ |
482 | handled = 1; | 455 | lance->RAP = CSR30; /* Base Address of Transmit Ring */ |
483 | ariadne_rx(dev); | 456 | lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, tx_ring)); |
484 | } | 457 | lance->RAP = CSR31; /* Base Address of transmit Ring */ |
458 | lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, tx_ring)); | ||
459 | |||
460 | /* Set the Receive Descriptor Ring Pointer */ | ||
461 | lance->RAP = CSR24; /* Base Address of Receive Ring */ | ||
462 | lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, rx_ring)); | ||
463 | lance->RAP = CSR25; /* Base Address of Receive Ring */ | ||
464 | lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, rx_ring)); | ||
465 | |||
466 | /* Set the Number of RX and TX Ring Entries */ | ||
467 | lance->RAP = CSR76; /* Receive Ring Length */ | ||
468 | lance->RDP = swapw(((u_short)-RX_RING_SIZE)); | ||
469 | lance->RAP = CSR78; /* Transmit Ring Length */ | ||
470 | lance->RDP = swapw(((u_short)-TX_RING_SIZE)); | ||
471 | |||
472 | /* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */ | ||
473 | lance->RAP = ISACSR2; /* Miscellaneous Configuration */ | ||
474 | lance->IDP = ASEL; | ||
475 | |||
476 | /* LED Control */ | ||
477 | lance->RAP = ISACSR5; /* LED1 Status */ | ||
478 | lance->IDP = PSE|XMTE; | ||
479 | lance->RAP = ISACSR6; /* LED2 Status */ | ||
480 | lance->IDP = PSE|COLE; | ||
481 | lance->RAP = ISACSR7; /* LED3 Status */ | ||
482 | lance->IDP = PSE|RCVE; | ||
483 | |||
484 | netif_start_queue(dev); | ||
485 | |||
486 | i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, IRQF_SHARED, | ||
487 | dev->name, dev); | ||
488 | if (i) | ||
489 | return i; | ||
490 | |||
491 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
492 | lance->RDP = INEA | STRT; | ||
493 | |||
494 | return 0; | ||
495 | } | ||
485 | 496 | ||
486 | if (csr0 & TINT) { /* Tx-done interrupt */ | 497 | static int ariadne_close(struct net_device *dev) |
487 | int dirty_tx = priv->dirty_tx; | 498 | { |
488 | 499 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; | |
489 | handled = 1; | ||
490 | while (dirty_tx < priv->cur_tx) { | ||
491 | int entry = dirty_tx % TX_RING_SIZE; | ||
492 | int status = lowb(priv->tx_ring[entry]->TMD1); | ||
493 | |||
494 | if (status & TF_OWN) | ||
495 | break; /* It still hasn't been Txed */ | ||
496 | |||
497 | priv->tx_ring[entry]->TMD1 &= 0xff00; | ||
498 | |||
499 | if (status & TF_ERR) { | ||
500 | /* There was an major error, log it. */ | ||
501 | int err_status = priv->tx_ring[entry]->TMD3; | ||
502 | dev->stats.tx_errors++; | ||
503 | if (err_status & EF_RTRY) | ||
504 | dev->stats.tx_aborted_errors++; | ||
505 | if (err_status & EF_LCAR) | ||
506 | dev->stats.tx_carrier_errors++; | ||
507 | if (err_status & EF_LCOL) | ||
508 | dev->stats.tx_window_errors++; | ||
509 | if (err_status & EF_UFLO) { | ||
510 | /* Ackk! On FIFO errors the Tx unit is turned off! */ | ||
511 | dev->stats.tx_fifo_errors++; | ||
512 | /* Remove this verbosity later! */ | ||
513 | printk(KERN_ERR "%s: Tx FIFO error! Status %4.4x.\n", | ||
514 | dev->name, csr0); | ||
515 | /* Restart the chip. */ | ||
516 | lance->RDP = STRT; | ||
517 | } | ||
518 | } else { | ||
519 | if (status & (TF_MORE|TF_ONE)) | ||
520 | dev->stats.collisions++; | ||
521 | dev->stats.tx_packets++; | ||
522 | } | ||
523 | dirty_tx++; | ||
524 | } | ||
525 | 500 | ||
526 | #ifndef final_version | 501 | netif_stop_queue(dev); |
527 | if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) { | ||
528 | printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, " | ||
529 | "full=%d.\n", dirty_tx, priv->cur_tx, priv->tx_full); | ||
530 | dirty_tx += TX_RING_SIZE; | ||
531 | } | ||
532 | #endif | ||
533 | 502 | ||
534 | if (priv->tx_full && netif_queue_stopped(dev) && | 503 | lance->RAP = CSR112; /* Missed Frame Count */ |
535 | dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) { | 504 | dev->stats.rx_missed_errors = swapw(lance->RDP); |
536 | /* The ring is no longer full. */ | 505 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ |
537 | priv->tx_full = 0; | ||
538 | netif_wake_queue(dev); | ||
539 | } | ||
540 | 506 | ||
541 | priv->dirty_tx = dirty_tx; | 507 | if (ariadne_debug > 1) { |
508 | netdev_dbg(dev, "Shutting down ethercard, status was %02x\n", | ||
509 | lance->RDP); | ||
510 | netdev_dbg(dev, "%lu packets missed\n", | ||
511 | dev->stats.rx_missed_errors); | ||
542 | } | 512 | } |
543 | 513 | ||
544 | /* Log misc errors. */ | 514 | /* We stop the LANCE here -- it occasionally polls memory if we don't */ |
545 | if (csr0 & BABL) { | 515 | lance->RDP = STOP; |
546 | handled = 1; | ||
547 | dev->stats.tx_errors++; /* Tx babble. */ | ||
548 | } | ||
549 | if (csr0 & MISS) { | ||
550 | handled = 1; | ||
551 | dev->stats.rx_errors++; /* Missed a Rx frame. */ | ||
552 | } | ||
553 | if (csr0 & MERR) { | ||
554 | handled = 1; | ||
555 | printk(KERN_ERR "%s: Bus master arbitration failure, status " | ||
556 | "%4.4x.\n", dev->name, csr0); | ||
557 | /* Restart the chip. */ | ||
558 | lance->RDP = STRT; | ||
559 | } | ||
560 | } | ||
561 | 516 | ||
562 | /* Clear any other interrupt, and set interrupt enable. */ | 517 | free_irq(IRQ_AMIGA_PORTS, dev); |
563 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
564 | lance->RDP = INEA|BABL|CERR|MISS|MERR|IDON; | ||
565 | 518 | ||
566 | #if 0 | 519 | return 0; |
567 | if (ariadne_debug > 4) | ||
568 | printk(KERN_DEBUG "%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, | ||
569 | lance->RAP, lance->RDP); | ||
570 | #endif | ||
571 | return IRQ_RETVAL(handled); | ||
572 | } | 520 | } |
573 | 521 | ||
522 | static inline void ariadne_reset(struct net_device *dev) | ||
523 | { | ||
524 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; | ||
525 | |||
526 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
527 | lance->RDP = STOP; | ||
528 | ariadne_init_ring(dev); | ||
529 | lance->RDP = INEA | STRT; | ||
530 | netif_start_queue(dev); | ||
531 | } | ||
574 | 532 | ||
575 | static void ariadne_tx_timeout(struct net_device *dev) | 533 | static void ariadne_tx_timeout(struct net_device *dev) |
576 | { | 534 | { |
577 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 535 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; |
578 | 536 | ||
579 | printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n", | 537 | netdev_err(dev, "transmit timed out, status %04x, resetting\n", |
580 | dev->name, lance->RDP); | 538 | lance->RDP); |
581 | ariadne_reset(dev); | 539 | ariadne_reset(dev); |
582 | netif_wake_queue(dev); | 540 | netif_wake_queue(dev); |
583 | } | 541 | } |
584 | 542 | ||
585 | |||
586 | static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, | 543 | static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, |
587 | struct net_device *dev) | 544 | struct net_device *dev) |
588 | { | 545 | { |
589 | struct ariadne_private *priv = netdev_priv(dev); | 546 | struct ariadne_private *priv = netdev_priv(dev); |
590 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 547 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; |
591 | int entry; | 548 | int entry; |
592 | unsigned long flags; | 549 | unsigned long flags; |
593 | int len = skb->len; | 550 | int len = skb->len; |
594 | |||
595 | #if 0 | ||
596 | if (ariadne_debug > 3) { | ||
597 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | ||
598 | printk(KERN_DEBUG "%s: ariadne_start_xmit() called, csr0 %4.4x.\n", | ||
599 | dev->name, lance->RDP); | ||
600 | lance->RDP = 0x0000; | ||
601 | } | ||
602 | #endif | ||
603 | |||
604 | /* FIXME: is the 79C960 new enough to do its own padding right ? */ | ||
605 | if (skb->len < ETH_ZLEN) | ||
606 | { | ||
607 | if (skb_padto(skb, ETH_ZLEN)) | ||
608 | return NETDEV_TX_OK; | ||
609 | len = ETH_ZLEN; | ||
610 | } | ||
611 | |||
612 | /* Fill in a Tx ring entry */ | ||
613 | 551 | ||
614 | #if 0 | 552 | #if 0 |
615 | { | 553 | if (ariadne_debug > 3) { |
616 | printk(KERN_DEBUG "TX pkt type 0x%04x from %pM to %pM " | 554 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ |
617 | " data 0x%08x len %d\n", | 555 | netdev_dbg(dev, "%s: csr0 %04x\n", __func__, lance->RDP); |
618 | ((u_short *)skb->data)[6], | 556 | lance->RDP = 0x0000; |
619 | skb->data + 6, skb->data, | 557 | } |
620 | (int)skb->data, (int)skb->len); | ||
621 | } | ||
622 | #endif | 558 | #endif |
623 | 559 | ||
624 | local_irq_save(flags); | 560 | /* FIXME: is the 79C960 new enough to do its own padding right ? */ |
625 | 561 | if (skb->len < ETH_ZLEN) { | |
626 | entry = priv->cur_tx % TX_RING_SIZE; | 562 | if (skb_padto(skb, ETH_ZLEN)) |
627 | 563 | return NETDEV_TX_OK; | |
628 | /* Caution: the write order is important here, set the base address with | 564 | len = ETH_ZLEN; |
629 | the "ownership" bits last. */ | ||
630 | |||
631 | priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len); | ||
632 | priv->tx_ring[entry]->TMD3 = 0x0000; | ||
633 | memcpyw(priv->tx_buff[entry], (u_short *)skb->data, len); | ||
634 | |||
635 | #if 0 | ||
636 | { | ||
637 | int i, len; | ||
638 | |||
639 | len = skb->len > 64 ? 64 : skb->len; | ||
640 | len >>= 1; | ||
641 | for (i = 0; i < len; i += 8) { | ||
642 | int j; | ||
643 | printk(KERN_DEBUG "%04x:", i); | ||
644 | for (j = 0; (j < 8) && ((i+j) < len); j++) { | ||
645 | if (!(j & 1)) | ||
646 | printk(" "); | ||
647 | printk("%04x", priv->tx_buff[entry][i+j]); | ||
648 | } | ||
649 | printk("\n"); | ||
650 | } | 565 | } |
651 | } | ||
652 | #endif | ||
653 | 566 | ||
654 | priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1&0xff00)|TF_OWN|TF_STP|TF_ENP; | 567 | /* Fill in a Tx ring entry */ |
655 | 568 | ||
656 | dev_kfree_skb(skb); | 569 | netdev_dbg(dev, "TX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n", |
570 | ((u_short *)skb->data)[6], | ||
571 | skb->data + 6, skb->data, | ||
572 | (int)skb->data, (int)skb->len); | ||
657 | 573 | ||
658 | priv->cur_tx++; | 574 | local_irq_save(flags); |
659 | if ((priv->cur_tx >= TX_RING_SIZE) && (priv->dirty_tx >= TX_RING_SIZE)) { | ||
660 | 575 | ||
661 | #if 0 | 576 | entry = priv->cur_tx % TX_RING_SIZE; |
662 | printk(KERN_DEBUG "*** Subtracting TX_RING_SIZE from cur_tx (%d) and " | ||
663 | "dirty_tx (%d)\n", priv->cur_tx, priv->dirty_tx); | ||
664 | #endif | ||
665 | 577 | ||
666 | priv->cur_tx -= TX_RING_SIZE; | 578 | /* Caution: the write order is important here, set the base address with |
667 | priv->dirty_tx -= TX_RING_SIZE; | 579 | the "ownership" bits last */ |
668 | } | ||
669 | dev->stats.tx_bytes += len; | ||
670 | 580 | ||
671 | /* Trigger an immediate send poll. */ | 581 | priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len); |
672 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | 582 | priv->tx_ring[entry]->TMD3 = 0x0000; |
673 | lance->RDP = INEA|TDMD; | 583 | memcpyw(priv->tx_buff[entry], (u_short *)skb->data, len); |
674 | 584 | ||
675 | if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) != 0) { | 585 | #ifdef DEBUG |
676 | netif_stop_queue(dev); | 586 | print_hex_dump(KERN_DEBUG, "tx_buff: ", DUMP_PREFIX_OFFSET, 16, 1, |
677 | priv->tx_full = 1; | 587 | (void *)priv->tx_buff[entry], |
678 | } | 588 | skb->len > 64 ? 64 : skb->len, true); |
679 | local_irq_restore(flags); | 589 | #endif |
680 | 590 | ||
681 | return NETDEV_TX_OK; | 591 | priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1 & 0xff00) |
682 | } | 592 | | TF_OWN | TF_STP | TF_ENP; |
683 | 593 | ||
594 | dev_kfree_skb(skb); | ||
684 | 595 | ||
685 | static int ariadne_rx(struct net_device *dev) | 596 | priv->cur_tx++; |
686 | { | 597 | if ((priv->cur_tx >= TX_RING_SIZE) && |
687 | struct ariadne_private *priv = netdev_priv(dev); | 598 | (priv->dirty_tx >= TX_RING_SIZE)) { |
688 | int entry = priv->cur_rx % RX_RING_SIZE; | ||
689 | int i; | ||
690 | |||
691 | /* If we own the next entry, it's a new packet. Send it up. */ | ||
692 | while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) { | ||
693 | int status = lowb(priv->rx_ring[entry]->RMD1); | ||
694 | |||
695 | if (status != (RF_STP|RF_ENP)) { /* There was an error. */ | ||
696 | /* There is a tricky error noted by John Murphy, | ||
697 | <murf@perftech.com> to Russ Nelson: Even with full-sized | ||
698 | buffers it's possible for a jabber packet to use two | ||
699 | buffers, with only the last correctly noting the error. */ | ||
700 | if (status & RF_ENP) | ||
701 | /* Only count a general error at the end of a packet.*/ | ||
702 | dev->stats.rx_errors++; | ||
703 | if (status & RF_FRAM) | ||
704 | dev->stats.rx_frame_errors++; | ||
705 | if (status & RF_OFLO) | ||
706 | dev->stats.rx_over_errors++; | ||
707 | if (status & RF_CRC) | ||
708 | dev->stats.rx_crc_errors++; | ||
709 | if (status & RF_BUFF) | ||
710 | dev->stats.rx_fifo_errors++; | ||
711 | priv->rx_ring[entry]->RMD1 &= 0xff00|RF_STP|RF_ENP; | ||
712 | } else { | ||
713 | /* Malloc up new buffer, compatible with net-3. */ | ||
714 | short pkt_len = swapw(priv->rx_ring[entry]->RMD3); | ||
715 | struct sk_buff *skb; | ||
716 | |||
717 | skb = dev_alloc_skb(pkt_len+2); | ||
718 | if (skb == NULL) { | ||
719 | printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n", | ||
720 | dev->name); | ||
721 | for (i = 0; i < RX_RING_SIZE; i++) | ||
722 | if (lowb(priv->rx_ring[(entry+i) % RX_RING_SIZE]->RMD1) & RF_OWN) | ||
723 | break; | ||
724 | |||
725 | if (i > RX_RING_SIZE-2) { | ||
726 | dev->stats.rx_dropped++; | ||
727 | priv->rx_ring[entry]->RMD1 |= RF_OWN; | ||
728 | priv->cur_rx++; | ||
729 | } | ||
730 | break; | ||
731 | } | ||
732 | 599 | ||
600 | netdev_dbg(dev, "*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n", | ||
601 | priv->cur_tx, priv->dirty_tx); | ||
733 | 602 | ||
734 | skb_reserve(skb,2); /* 16 byte align */ | 603 | priv->cur_tx -= TX_RING_SIZE; |
735 | skb_put(skb,pkt_len); /* Make room */ | 604 | priv->dirty_tx -= TX_RING_SIZE; |
736 | skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len); | ||
737 | skb->protocol=eth_type_trans(skb,dev); | ||
738 | #if 0 | ||
739 | { | ||
740 | printk(KERN_DEBUG "RX pkt type 0x%04x from ", | ||
741 | ((u_short *)skb->data)[6]); | ||
742 | { | ||
743 | u_char *ptr = &((u_char *)skb->data)[6]; | ||
744 | printk("%pM", ptr); | ||
745 | } | ||
746 | printk(" to "); | ||
747 | { | ||
748 | u_char *ptr = (u_char *)skb->data; | ||
749 | printk("%pM", ptr); | ||
750 | } | ||
751 | printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); | ||
752 | } | ||
753 | #endif | ||
754 | |||
755 | netif_rx(skb); | ||
756 | dev->stats.rx_packets++; | ||
757 | dev->stats.rx_bytes += pkt_len; | ||
758 | } | 605 | } |
606 | dev->stats.tx_bytes += len; | ||
759 | 607 | ||
760 | priv->rx_ring[entry]->RMD1 |= RF_OWN; | 608 | /* Trigger an immediate send poll */ |
761 | entry = (++priv->cur_rx) % RX_RING_SIZE; | 609 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ |
762 | } | 610 | lance->RDP = INEA | TDMD; |
763 | 611 | ||
764 | priv->cur_rx = priv->cur_rx % RX_RING_SIZE; | 612 | if (lowb(priv->tx_ring[(entry + 1) % TX_RING_SIZE]->TMD1) != 0) { |
765 | 613 | netif_stop_queue(dev); | |
766 | /* We should check that at least two ring entries are free. If not, | 614 | priv->tx_full = 1; |
767 | we should free one and mark stats->rx_dropped++. */ | 615 | } |
616 | local_irq_restore(flags); | ||
768 | 617 | ||
769 | return 0; | 618 | return NETDEV_TX_OK; |
770 | } | 619 | } |
771 | 620 | ||
772 | |||
773 | static struct net_device_stats *ariadne_get_stats(struct net_device *dev) | 621 | static struct net_device_stats *ariadne_get_stats(struct net_device *dev) |
774 | { | 622 | { |
775 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 623 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; |
776 | short saved_addr; | 624 | short saved_addr; |
777 | unsigned long flags; | 625 | unsigned long flags; |
778 | 626 | ||
779 | local_irq_save(flags); | 627 | local_irq_save(flags); |
780 | saved_addr = lance->RAP; | 628 | saved_addr = lance->RAP; |
781 | lance->RAP = CSR112; /* Missed Frame Count */ | 629 | lance->RAP = CSR112; /* Missed Frame Count */ |
782 | dev->stats.rx_missed_errors = swapw(lance->RDP); | 630 | dev->stats.rx_missed_errors = swapw(lance->RDP); |
783 | lance->RAP = saved_addr; | 631 | lance->RAP = saved_addr; |
784 | local_irq_restore(flags); | 632 | local_irq_restore(flags); |
785 | 633 | ||
786 | return &dev->stats; | 634 | return &dev->stats; |
787 | } | 635 | } |
788 | 636 | ||
789 | |||
790 | /* Set or clear the multicast filter for this adaptor. | 637 | /* Set or clear the multicast filter for this adaptor. |
791 | num_addrs == -1 Promiscuous mode, receive all packets | 638 | * num_addrs == -1 Promiscuous mode, receive all packets |
792 | num_addrs == 0 Normal mode, clear multicast list | 639 | * num_addrs == 0 Normal mode, clear multicast list |
793 | num_addrs > 0 Multicast mode, receive normal and MC packets, and do | 640 | * num_addrs > 0 Multicast mode, receive normal and MC packets, |
794 | best-effort filtering. | 641 | * and do best-effort filtering. |
795 | */ | 642 | */ |
796 | static void set_multicast_list(struct net_device *dev) | 643 | static void set_multicast_list(struct net_device *dev) |
797 | { | 644 | { |
798 | volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; | 645 | volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; |
799 | 646 | ||
800 | if (!netif_running(dev)) | 647 | if (!netif_running(dev)) |
801 | return; | 648 | return; |
802 | 649 | ||
803 | netif_stop_queue(dev); | 650 | netif_stop_queue(dev); |
804 | 651 | ||
805 | /* We take the simple way out and always enable promiscuous mode. */ | 652 | /* We take the simple way out and always enable promiscuous mode */ |
806 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | 653 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ |
807 | lance->RDP = STOP; /* Temporarily stop the lance. */ | 654 | lance->RDP = STOP; /* Temporarily stop the lance */ |
808 | ariadne_init_ring(dev); | 655 | ariadne_init_ring(dev); |
809 | 656 | ||
810 | if (dev->flags & IFF_PROMISC) { | 657 | if (dev->flags & IFF_PROMISC) { |
811 | lance->RAP = CSR15; /* Mode Register */ | 658 | lance->RAP = CSR15; /* Mode Register */ |
812 | lance->RDP = PROM; /* Set promiscuous mode */ | 659 | lance->RDP = PROM; /* Set promiscuous mode */ |
813 | } else { | 660 | } else { |
814 | short multicast_table[4]; | 661 | short multicast_table[4]; |
815 | int num_addrs = netdev_mc_count(dev); | 662 | int num_addrs = netdev_mc_count(dev); |
816 | int i; | 663 | int i; |
817 | /* We don't use the multicast table, but rely on upper-layer filtering. */ | 664 | /* We don't use the multicast table, |
818 | memset(multicast_table, (num_addrs == 0) ? 0 : -1, | 665 | * but rely on upper-layer filtering |
819 | sizeof(multicast_table)); | 666 | */ |
820 | for (i = 0; i < 4; i++) { | 667 | memset(multicast_table, (num_addrs == 0) ? 0 : -1, |
821 | lance->RAP = CSR8+(i<<8); /* Logical Address Filter */ | 668 | sizeof(multicast_table)); |
822 | lance->RDP = swapw(multicast_table[i]); | 669 | for (i = 0; i < 4; i++) { |
670 | lance->RAP = CSR8 + (i << 8); | ||
671 | /* Logical Address Filter */ | ||
672 | lance->RDP = swapw(multicast_table[i]); | ||
673 | } | ||
674 | lance->RAP = CSR15; /* Mode Register */ | ||
675 | lance->RDP = 0x0000; /* Unset promiscuous mode */ | ||
823 | } | 676 | } |
824 | lance->RAP = CSR15; /* Mode Register */ | ||
825 | lance->RDP = 0x0000; /* Unset promiscuous mode */ | ||
826 | } | ||
827 | 677 | ||
828 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ | 678 | lance->RAP = CSR0; /* PCnet-ISA Controller Status */ |
829 | lance->RDP = INEA|STRT|IDON; /* Resume normal operation. */ | 679 | lance->RDP = INEA | STRT | IDON;/* Resume normal operation */ |
830 | 680 | ||
831 | netif_wake_queue(dev); | 681 | netif_wake_queue(dev); |
832 | } | 682 | } |
833 | 683 | ||
834 | 684 | ||
835 | static void __devexit ariadne_remove_one(struct zorro_dev *z) | 685 | static void __devexit ariadne_remove_one(struct zorro_dev *z) |
836 | { | 686 | { |
837 | struct net_device *dev = zorro_get_drvdata(z); | 687 | struct net_device *dev = zorro_get_drvdata(z); |
838 | 688 | ||
839 | unregister_netdev(dev); | 689 | unregister_netdev(dev); |
840 | release_mem_region(ZTWO_PADDR(dev->base_addr), sizeof(struct Am79C960)); | 690 | release_mem_region(ZTWO_PADDR(dev->base_addr), sizeof(struct Am79C960)); |
841 | release_mem_region(ZTWO_PADDR(dev->mem_start), ARIADNE_RAM_SIZE); | 691 | release_mem_region(ZTWO_PADDR(dev->mem_start), ARIADNE_RAM_SIZE); |
842 | free_netdev(dev); | 692 | free_netdev(dev); |
843 | } | 693 | } |
844 | 694 | ||
695 | static struct zorro_device_id ariadne_zorro_tbl[] __devinitdata = { | ||
696 | { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE }, | ||
697 | { 0 } | ||
698 | }; | ||
699 | MODULE_DEVICE_TABLE(zorro, ariadne_zorro_tbl); | ||
700 | |||
701 | static const struct net_device_ops ariadne_netdev_ops = { | ||
702 | .ndo_open = ariadne_open, | ||
703 | .ndo_stop = ariadne_close, | ||
704 | .ndo_start_xmit = ariadne_start_xmit, | ||
705 | .ndo_tx_timeout = ariadne_tx_timeout, | ||
706 | .ndo_get_stats = ariadne_get_stats, | ||
707 | .ndo_set_multicast_list = set_multicast_list, | ||
708 | .ndo_validate_addr = eth_validate_addr, | ||
709 | .ndo_change_mtu = eth_change_mtu, | ||
710 | .ndo_set_mac_address = eth_mac_addr, | ||
711 | }; | ||
712 | |||
713 | static int __devinit ariadne_init_one(struct zorro_dev *z, | ||
714 | const struct zorro_device_id *ent) | ||
715 | { | ||
716 | unsigned long board = z->resource.start; | ||
717 | unsigned long base_addr = board + ARIADNE_LANCE; | ||
718 | unsigned long mem_start = board + ARIADNE_RAM; | ||
719 | struct resource *r1, *r2; | ||
720 | struct net_device *dev; | ||
721 | struct ariadne_private *priv; | ||
722 | int err; | ||
723 | |||
724 | r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960"); | ||
725 | if (!r1) | ||
726 | return -EBUSY; | ||
727 | r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); | ||
728 | if (!r2) { | ||
729 | release_mem_region(base_addr, sizeof(struct Am79C960)); | ||
730 | return -EBUSY; | ||
731 | } | ||
732 | |||
733 | dev = alloc_etherdev(sizeof(struct ariadne_private)); | ||
734 | if (dev == NULL) { | ||
735 | release_mem_region(base_addr, sizeof(struct Am79C960)); | ||
736 | release_mem_region(mem_start, ARIADNE_RAM_SIZE); | ||
737 | return -ENOMEM; | ||
738 | } | ||
739 | |||
740 | priv = netdev_priv(dev); | ||
741 | |||
742 | r1->name = dev->name; | ||
743 | r2->name = dev->name; | ||
744 | |||
745 | dev->dev_addr[0] = 0x00; | ||
746 | dev->dev_addr[1] = 0x60; | ||
747 | dev->dev_addr[2] = 0x30; | ||
748 | dev->dev_addr[3] = (z->rom.er_SerialNumber >> 16) & 0xff; | ||
749 | dev->dev_addr[4] = (z->rom.er_SerialNumber >> 8) & 0xff; | ||
750 | dev->dev_addr[5] = z->rom.er_SerialNumber & 0xff; | ||
751 | dev->base_addr = ZTWO_VADDR(base_addr); | ||
752 | dev->mem_start = ZTWO_VADDR(mem_start); | ||
753 | dev->mem_end = dev->mem_start + ARIADNE_RAM_SIZE; | ||
754 | |||
755 | dev->netdev_ops = &ariadne_netdev_ops; | ||
756 | dev->watchdog_timeo = 5 * HZ; | ||
757 | |||
758 | err = register_netdev(dev); | ||
759 | if (err) { | ||
760 | release_mem_region(base_addr, sizeof(struct Am79C960)); | ||
761 | release_mem_region(mem_start, ARIADNE_RAM_SIZE); | ||
762 | free_netdev(dev); | ||
763 | return err; | ||
764 | } | ||
765 | zorro_set_drvdata(z, dev); | ||
766 | |||
767 | netdev_info(dev, "Ariadne at 0x%08lx, Ethernet Address %pM\n", | ||
768 | board, dev->dev_addr); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static struct zorro_driver ariadne_driver = { | ||
774 | .name = "ariadne", | ||
775 | .id_table = ariadne_zorro_tbl, | ||
776 | .probe = ariadne_init_one, | ||
777 | .remove = __devexit_p(ariadne_remove_one), | ||
778 | }; | ||
779 | |||
845 | static int __init ariadne_init_module(void) | 780 | static int __init ariadne_init_module(void) |
846 | { | 781 | { |
847 | return zorro_register_driver(&ariadne_driver); | 782 | return zorro_register_driver(&ariadne_driver); |
848 | } | 783 | } |
849 | 784 | ||
850 | static void __exit ariadne_cleanup_module(void) | 785 | static void __exit ariadne_cleanup_module(void) |
851 | { | 786 | { |
852 | zorro_unregister_driver(&ariadne_driver); | 787 | zorro_unregister_driver(&ariadne_driver); |
853 | } | 788 | } |
854 | 789 | ||
855 | module_init(ariadne_init_module); | 790 | module_init(ariadne_init_module); |