cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nfeth.c (6294B)


      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
     24enum {
     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. */
     42static const char version[] =
     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
     47MODULE_AUTHOR("Milan Jurik");
     48MODULE_DESCRIPTION("Atari NFeth driver");
     49MODULE_LICENSE("GPL");
     50
     51
     52static long nfEtherID;
     53static int nfEtherIRQ;
     54
     55struct nfeth_private {
     56	int ethX;
     57};
     58
     59static struct net_device *nfeth_dev[MAX_UNIT];
     60
     61static 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
     75static 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 */
     90static 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
    130static 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
    144static 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
    170static void nfeth_tx_timeout(struct net_device *dev, unsigned int txqueue)
    171{
    172	dev->stats.tx_errors++;
    173	netif_wake_queue(dev);
    174}
    175
    176static 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
    185static 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
    225static 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
    251static 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
    264module_init(nfeth_init);
    265module_exit(nfeth_cleanup);