xref: /linux/arch/m68k/emu/nfeth.c (revision b1a54551dd9ed5ef1763b97b35a0999ca002b95c)
1 /*
2  * atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux
3  *
4  * Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team
5  *
6  * Based on ARAnyM driver for FreeMiNT written by Standa Opichal
7  *
8  * This software may be used and distributed according to the terms of
9  * the GNU General Public License (GPL), incorporated herein by reference.
10  */
11 
12 #define DRV_VERSION	"0.3"
13 #define DRV_RELDATE	"10/12/2005"
14 
15 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
16 
17 #include <linux/netdevice.h>
18 #include <linux/etherdevice.h>
19 #include <linux/interrupt.h>
20 #include <linux/module.h>
21 #include <asm/natfeat.h>
22 #include <asm/virtconvert.h>
23 
24 enum {
25 	GET_VERSION = 0,/* no parameters, return NFAPI_VERSION in d0 */
26 	XIF_INTLEVEL,	/* no parameters, return Interrupt Level in d0 */
27 	XIF_IRQ,	/* acknowledge interrupt from host */
28 	XIF_START,	/* (ethX), called on 'ifup', start receiver thread */
29 	XIF_STOP,	/* (ethX), called on 'ifdown', stop the thread */
30 	XIF_READLENGTH,	/* (ethX), return size of network data block to read */
31 	XIF_READBLOCK,	/* (ethX, buffer, size), read block of network data */
32 	XIF_WRITEBLOCK,	/* (ethX, buffer, size), write block of network data */
33 	XIF_GET_MAC,	/* (ethX, buffer, size), return MAC HW addr in buffer */
34 	XIF_GET_IPHOST,	/* (ethX, buffer, size), return IP address of host */
35 	XIF_GET_IPATARI,/* (ethX, buffer, size), return IP address of atari */
36 	XIF_GET_NETMASK	/* (ethX, buffer, size), return IP netmask */
37 };
38 
39 #define MAX_UNIT	8
40 
41 /* These identify the driver base version and may not be removed. */
42 static const char version[] __maybe_unused =
43 	KERN_INFO KBUILD_MODNAME ".c:v" DRV_VERSION " " DRV_RELDATE
44 	" S.Opichal, M.Jurik, P.Stehlik\n"
45 	KERN_INFO " http://aranym.org/\n";
46 
47 MODULE_AUTHOR("Milan Jurik");
48 MODULE_DESCRIPTION("Atari NFeth driver");
49 MODULE_LICENSE("GPL");
50 
51 
52 static long nfEtherID;
53 static int nfEtherIRQ;
54 
55 struct nfeth_private {
56 	int ethX;
57 };
58 
59 static struct net_device *nfeth_dev[MAX_UNIT];
60 
61 static int nfeth_open(struct net_device *dev)
62 {
63 	struct nfeth_private *priv = netdev_priv(dev);
64 	int res;
65 
66 	res = nf_call(nfEtherID + XIF_START, priv->ethX);
67 	netdev_dbg(dev, "%s: %d\n", __func__, res);
68 
69 	/* Ready for data */
70 	netif_start_queue(dev);
71 
72 	return 0;
73 }
74 
75 static int nfeth_stop(struct net_device *dev)
76 {
77 	struct nfeth_private *priv = netdev_priv(dev);
78 
79 	/* No more data */
80 	netif_stop_queue(dev);
81 
82 	nf_call(nfEtherID + XIF_STOP, priv->ethX);
83 
84 	return 0;
85 }
86 
87 /*
88  * Read a packet out of the adapter and pass it to the upper layers
89  */
90 static inline void recv_packet(struct net_device *dev)
91 {
92 	struct nfeth_private *priv = netdev_priv(dev);
93 	unsigned short pktlen;
94 	struct sk_buff *skb;
95 
96 	/* read packet length (excluding 32 bit crc) */
97 	pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX);
98 
99 	netdev_dbg(dev, "%s: %u\n", __func__, pktlen);
100 
101 	if (!pktlen) {
102 		netdev_dbg(dev, "%s: pktlen == 0\n", __func__);
103 		dev->stats.rx_errors++;
104 		return;
105 	}
106 
107 	skb = dev_alloc_skb(pktlen + 2);
108 	if (!skb) {
109 		netdev_dbg(dev, "%s: out of mem (buf_alloc failed)\n",
110 			   __func__);
111 		dev->stats.rx_dropped++;
112 		return;
113 	}
114 
115 	skb->dev = dev;
116 	skb_reserve(skb, 2);		/* 16 Byte align  */
117 	skb_put(skb, pktlen);		/* make room */
118 	nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data),
119 		pktlen);
120 
121 	skb->protocol = eth_type_trans(skb, dev);
122 	netif_rx(skb);
123 	dev->stats.rx_packets++;
124 	dev->stats.rx_bytes += pktlen;
125 
126 	/* and enqueue packet */
127 	return;
128 }
129 
130 static irqreturn_t nfeth_interrupt(int irq, void *dev_id)
131 {
132 	int i, m, mask;
133 
134 	mask = nf_call(nfEtherID + XIF_IRQ, 0);
135 	for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) {
136 		if (mask & m && nfeth_dev[i]) {
137 			recv_packet(nfeth_dev[i]);
138 			nf_call(nfEtherID + XIF_IRQ, m);
139 		}
140 	}
141 	return IRQ_HANDLED;
142 }
143 
144 static int nfeth_xmit(struct sk_buff *skb, struct net_device *dev)
145 {
146 	unsigned int len;
147 	char *data, shortpkt[ETH_ZLEN];
148 	struct nfeth_private *priv = netdev_priv(dev);
149 
150 	data = skb->data;
151 	len = skb->len;
152 	if (len < ETH_ZLEN) {
153 		memset(shortpkt, 0, ETH_ZLEN);
154 		memcpy(shortpkt, data, len);
155 		data = shortpkt;
156 		len = ETH_ZLEN;
157 	}
158 
159 	netdev_dbg(dev, "%s: send %u bytes\n", __func__, len);
160 	nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data),
161 		len);
162 
163 	dev->stats.tx_packets++;
164 	dev->stats.tx_bytes += len;
165 
166 	dev_kfree_skb(skb);
167 	return 0;
168 }
169 
170 static void nfeth_tx_timeout(struct net_device *dev, unsigned int txqueue)
171 {
172 	dev->stats.tx_errors++;
173 	netif_wake_queue(dev);
174 }
175 
176 static const struct net_device_ops nfeth_netdev_ops = {
177 	.ndo_open		= nfeth_open,
178 	.ndo_stop		= nfeth_stop,
179 	.ndo_start_xmit		= nfeth_xmit,
180 	.ndo_tx_timeout		= nfeth_tx_timeout,
181 	.ndo_validate_addr	= eth_validate_addr,
182 	.ndo_set_mac_address	= eth_mac_addr,
183 };
184 
185 static struct net_device * __init nfeth_probe(int unit)
186 {
187 	struct net_device *dev;
188 	struct nfeth_private *priv;
189 	char mac[ETH_ALEN], host_ip[32], local_ip[32];
190 	int err;
191 
192 	if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac),
193 		     ETH_ALEN))
194 		return NULL;
195 
196 	dev = alloc_etherdev(sizeof(struct nfeth_private));
197 	if (!dev)
198 		return NULL;
199 
200 	dev->irq = nfEtherIRQ;
201 	dev->netdev_ops = &nfeth_netdev_ops;
202 
203 	eth_hw_addr_set(dev, mac);
204 
205 	priv = netdev_priv(dev);
206 	priv->ethX = unit;
207 
208 	err = register_netdev(dev);
209 	if (err) {
210 		free_netdev(dev);
211 		return NULL;
212 	}
213 
214 	nf_call(nfEtherID + XIF_GET_IPHOST, unit,
215 		virt_to_phys(host_ip), sizeof(host_ip));
216 	nf_call(nfEtherID + XIF_GET_IPATARI, unit,
217 		virt_to_phys(local_ip), sizeof(local_ip));
218 
219 	netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip,
220 		    local_ip, mac);
221 
222 	return dev;
223 }
224 
225 static int __init nfeth_init(void)
226 {
227 	long ver;
228 	int error, i;
229 
230 	nfEtherID = nf_get_id("ETHERNET");
231 	if (!nfEtherID)
232 		return -ENODEV;
233 
234 	ver = nf_call(nfEtherID + GET_VERSION);
235 	pr_info("API %lu\n", ver);
236 
237 	nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL);
238 	error = request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED,
239 			    "eth emu", nfeth_interrupt);
240 	if (error) {
241 		pr_err("request for irq %d failed %d", nfEtherIRQ, error);
242 		return error;
243 	}
244 
245 	for (i = 0; i < MAX_UNIT; i++)
246 		nfeth_dev[i] = nfeth_probe(i);
247 
248 	return 0;
249 }
250 
251 static void __exit nfeth_cleanup(void)
252 {
253 	int i;
254 
255 	for (i = 0; i < MAX_UNIT; i++) {
256 		if (nfeth_dev[i]) {
257 			unregister_netdev(nfeth_dev[i]);
258 			free_netdev(nfeth_dev[i]);
259 		}
260 	}
261 	free_irq(nfEtherIRQ, nfeth_interrupt);
262 }
263 
264 module_init(nfeth_init);
265 module_exit(nfeth_cleanup);
266