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