1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | |
3 | /* New Hydra driver using generic 8390 core */ |
4 | /* Based on old hydra driver by Topi Kanerva (topi@susanna.oulu.fi) */ |
5 | |
6 | /* Peter De Schrijver (p2@mind.be) */ |
7 | /* Oldenburg 2000 */ |
8 | |
9 | /* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a */ |
10 | /* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM */ |
11 | /* and 10BASE-2 (thin coax) and AUI connectors. */ |
12 | |
13 | #include <linux/module.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/string.h> |
16 | #include <linux/errno.h> |
17 | #include <linux/ioport.h> |
18 | #include <linux/interrupt.h> |
19 | #include <linux/netdevice.h> |
20 | #include <linux/etherdevice.h> |
21 | #include <linux/skbuff.h> |
22 | #include <linux/init.h> |
23 | #include <linux/bitops.h> |
24 | |
25 | #include <asm/io.h> |
26 | #include <asm/irq.h> |
27 | #include <asm/amigaints.h> |
28 | #include <asm/amigahw.h> |
29 | #include <linux/zorro.h> |
30 | |
31 | #define EI_SHIFT(x) (ei_local->reg_offset[x]) |
32 | #define ei_inb(port) in_8(port) |
33 | #define ei_outb(val,port) out_8(port,val) |
34 | #define ei_inb_p(port) in_8(port) |
35 | #define ei_outb_p(val,port) out_8(port,val) |
36 | |
37 | static const char version[] = |
38 | "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n" ; |
39 | |
40 | #include "lib8390.c" |
41 | |
42 | #define NE_EN0_DCFG (0x0e*2) |
43 | |
44 | #define NESM_START_PG 0x0 /* First page of TX buffer */ |
45 | #define NESM_STOP_PG 0x40 /* Last page +1 of RX ring */ |
46 | |
47 | #define HYDRA_NIC_BASE 0xffe1 |
48 | #define HYDRA_ADDRPROM 0xffc0 |
49 | #define HYDRA_VERSION "v3.0alpha" |
50 | |
51 | #define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) |
52 | |
53 | |
54 | static int hydra_init_one(struct zorro_dev *z, |
55 | const struct zorro_device_id *ent); |
56 | static int hydra_init(struct zorro_dev *z); |
57 | static int hydra_open(struct net_device *dev); |
58 | static int hydra_close(struct net_device *dev); |
59 | static void hydra_reset_8390(struct net_device *dev); |
60 | static void hydra_get_8390_hdr(struct net_device *dev, |
61 | struct e8390_pkt_hdr *hdr, int ring_page); |
62 | static void hydra_block_input(struct net_device *dev, int count, |
63 | struct sk_buff *skb, int ring_offset); |
64 | static void hydra_block_output(struct net_device *dev, int count, |
65 | const unsigned char *buf, int start_page); |
66 | static void hydra_remove_one(struct zorro_dev *z); |
67 | |
68 | static struct zorro_device_id hydra_zorro_tbl[] = { |
69 | { ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET }, |
70 | { 0 } |
71 | }; |
72 | MODULE_DEVICE_TABLE(zorro, hydra_zorro_tbl); |
73 | |
74 | static struct zorro_driver hydra_driver = { |
75 | .name = "hydra" , |
76 | .id_table = hydra_zorro_tbl, |
77 | .probe = hydra_init_one, |
78 | .remove = hydra_remove_one, |
79 | }; |
80 | |
81 | static int hydra_init_one(struct zorro_dev *z, |
82 | const struct zorro_device_id *ent) |
83 | { |
84 | int err; |
85 | |
86 | if (!request_mem_region(z->resource.start, 0x10000, "Hydra" )) |
87 | return -EBUSY; |
88 | if ((err = hydra_init(z))) { |
89 | release_mem_region(z->resource.start, 0x10000); |
90 | return -EBUSY; |
91 | } |
92 | return 0; |
93 | } |
94 | |
95 | static const struct net_device_ops hydra_netdev_ops = { |
96 | .ndo_open = hydra_open, |
97 | .ndo_stop = hydra_close, |
98 | |
99 | .ndo_start_xmit = __ei_start_xmit, |
100 | .ndo_tx_timeout = __ei_tx_timeout, |
101 | .ndo_get_stats = __ei_get_stats, |
102 | .ndo_set_rx_mode = __ei_set_multicast_list, |
103 | .ndo_validate_addr = eth_validate_addr, |
104 | .ndo_set_mac_address = eth_mac_addr, |
105 | #ifdef CONFIG_NET_POLL_CONTROLLER |
106 | .ndo_poll_controller = __ei_poll, |
107 | #endif |
108 | }; |
109 | |
110 | static int hydra_init(struct zorro_dev *z) |
111 | { |
112 | struct net_device *dev; |
113 | unsigned long board = (unsigned long)ZTWO_VADDR(z->resource.start); |
114 | unsigned long ioaddr = board+HYDRA_NIC_BASE; |
115 | const char name[] = "NE2000" ; |
116 | int start_page, stop_page; |
117 | u8 macaddr[ETH_ALEN]; |
118 | int j; |
119 | int err; |
120 | |
121 | static u32 hydra_offsets[16] = { |
122 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, |
123 | 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, |
124 | }; |
125 | |
126 | dev = ____alloc_ei_netdev(size: 0); |
127 | if (!dev) |
128 | return -ENOMEM; |
129 | |
130 | for (j = 0; j < ETH_ALEN; j++) |
131 | macaddr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j)); |
132 | eth_hw_addr_set(dev, addr: macaddr); |
133 | |
134 | /* We must set the 8390 for word mode. */ |
135 | z_writeb(0x4b, ioaddr + NE_EN0_DCFG); |
136 | start_page = NESM_START_PG; |
137 | stop_page = NESM_STOP_PG; |
138 | |
139 | dev->base_addr = ioaddr; |
140 | dev->irq = IRQ_AMIGA_PORTS; |
141 | |
142 | /* Install the Interrupt handler */ |
143 | if (request_irq(irq: IRQ_AMIGA_PORTS, handler: __ei_interrupt, IRQF_SHARED, name: "Hydra Ethernet" , |
144 | dev)) { |
145 | free_netdev(dev); |
146 | return -EAGAIN; |
147 | } |
148 | |
149 | ei_status.name = name; |
150 | ei_status.tx_start_page = start_page; |
151 | ei_status.stop_page = stop_page; |
152 | ei_status.word16 = 1; |
153 | ei_status.bigendian = 1; |
154 | |
155 | ei_status.rx_start_page = start_page + TX_PAGES; |
156 | |
157 | ei_status.reset_8390 = hydra_reset_8390; |
158 | ei_status.block_input = hydra_block_input; |
159 | ei_status.block_output = hydra_block_output; |
160 | ei_status.get_8390_hdr = hydra_get_8390_hdr; |
161 | ei_status.reg_offset = hydra_offsets; |
162 | |
163 | dev->netdev_ops = &hydra_netdev_ops; |
164 | __NS8390_init(dev, startp: 0); |
165 | |
166 | err = register_netdev(dev); |
167 | if (err) { |
168 | free_irq(IRQ_AMIGA_PORTS, dev); |
169 | free_netdev(dev); |
170 | return err; |
171 | } |
172 | |
173 | zorro_set_drvdata(z, data: dev); |
174 | |
175 | pr_info("%s: Hydra at %pR, address %pM (hydra.c " HYDRA_VERSION ")\n" , |
176 | dev->name, &z->resource, dev->dev_addr); |
177 | |
178 | return 0; |
179 | } |
180 | |
181 | static int hydra_open(struct net_device *dev) |
182 | { |
183 | __ei_open(dev); |
184 | return 0; |
185 | } |
186 | |
187 | static int hydra_close(struct net_device *dev) |
188 | { |
189 | struct ei_device *ei_local = netdev_priv(dev); |
190 | |
191 | netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n" ); |
192 | __ei_close(dev); |
193 | return 0; |
194 | } |
195 | |
196 | static void hydra_reset_8390(struct net_device *dev) |
197 | { |
198 | netdev_info(dev, format: "Hydra hw reset not there\n" ); |
199 | } |
200 | |
201 | static void hydra_get_8390_hdr(struct net_device *dev, |
202 | struct e8390_pkt_hdr *hdr, int ring_page) |
203 | { |
204 | int nic_base = dev->base_addr; |
205 | short *ptrs; |
206 | unsigned long hdr_start= (nic_base-HYDRA_NIC_BASE) + |
207 | ((ring_page - NESM_START_PG)<<8); |
208 | ptrs = (short *)hdr; |
209 | |
210 | *(ptrs++) = z_readw(hdr_start); |
211 | *((short *)hdr) = WORDSWAP(*((short *)hdr)); |
212 | hdr_start += 2; |
213 | *(ptrs++) = z_readw(hdr_start); |
214 | *((short *)hdr+1) = WORDSWAP(*((short *)hdr+1)); |
215 | } |
216 | |
217 | static void hydra_block_input(struct net_device *dev, int count, |
218 | struct sk_buff *skb, int ring_offset) |
219 | { |
220 | unsigned long nic_base = dev->base_addr; |
221 | unsigned long mem_base = nic_base - HYDRA_NIC_BASE; |
222 | unsigned long xfer_start = mem_base + ring_offset - (NESM_START_PG<<8); |
223 | |
224 | if (count&1) |
225 | count++; |
226 | |
227 | if (xfer_start+count > mem_base + (NESM_STOP_PG<<8)) { |
228 | int semi_count = (mem_base + (NESM_STOP_PG<<8)) - xfer_start; |
229 | |
230 | z_memcpy_fromio(skb->data,xfer_start,semi_count); |
231 | count -= semi_count; |
232 | z_memcpy_fromio(skb->data+semi_count, mem_base, count); |
233 | } else |
234 | z_memcpy_fromio(skb->data, xfer_start,count); |
235 | |
236 | } |
237 | |
238 | static void hydra_block_output(struct net_device *dev, int count, |
239 | const unsigned char *buf, int start_page) |
240 | { |
241 | unsigned long nic_base = dev->base_addr; |
242 | unsigned long mem_base = nic_base - HYDRA_NIC_BASE; |
243 | |
244 | if (count&1) |
245 | count++; |
246 | |
247 | z_memcpy_toio(mem_base+((start_page - NESM_START_PG)<<8), buf, count); |
248 | } |
249 | |
250 | static void hydra_remove_one(struct zorro_dev *z) |
251 | { |
252 | struct net_device *dev = zorro_get_drvdata(z); |
253 | |
254 | unregister_netdev(dev); |
255 | free_irq(IRQ_AMIGA_PORTS, dev); |
256 | release_mem_region(ZTWO_PADDR(dev->base_addr)-HYDRA_NIC_BASE, 0x10000); |
257 | free_netdev(dev); |
258 | } |
259 | |
260 | static int __init hydra_init_module(void) |
261 | { |
262 | return zorro_register_driver(&hydra_driver); |
263 | } |
264 | |
265 | static void __exit hydra_cleanup_module(void) |
266 | { |
267 | zorro_unregister_driver(&hydra_driver); |
268 | } |
269 | |
270 | module_init(hydra_init_module); |
271 | module_exit(hydra_cleanup_module); |
272 | |
273 | MODULE_LICENSE("GPL" ); |
274 | |