brintos

brintos / linux-shallow public Read only

0
0
Text · 22.6 KiB · 4a0a095 Raw
849 lines · c
1// SPDX-License-Identifier: GPL-1.0+2/* mac8390.c: New driver for 8390-based Nubus (or Nubus-alike)3   Ethernet cards on Linux */4/* Based on the former daynaport.c driver, by Alan Cox.  Some code5   taken from or inspired by skeleton.c by Donald Becker, acenic.c by6   Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker. */7 8/* 2000-02-28: support added for Dayna and Kinetics cards by9   A.G.deWijn@phys.uu.nl */10/* 2000-04-04: support added for Dayna2 by bart@etpmod.phys.tue.nl */11/* 2001-04-18: support for DaynaPort E/LC-M by rayk@knightsmanor.org */12/* 2001-05-15: support for Cabletron ported from old daynaport driver13 * and fixed access to Sonic Sys card which masquerades as a Farallon14 * by rayk@knightsmanor.org */15/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */16/* 2003-12-26: Make sure Asante cards always work. */17 18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt19 20#include <linux/module.h>21#include <linux/kernel.h>22#include <linux/types.h>23#include <linux/fcntl.h>24#include <linux/interrupt.h>25#include <linux/ptrace.h>26#include <linux/ioport.h>27#include <linux/nubus.h>28#include <linux/in.h>29#include <linux/string.h>30#include <linux/errno.h>31#include <linux/init.h>32#include <linux/netdevice.h>33#include <linux/etherdevice.h>34#include <linux/skbuff.h>35#include <linux/bitops.h>36#include <linux/io.h>37 38#include <asm/dma.h>39#include <asm/hwtest.h>40#include <asm/macints.h>41 42static char version[] =43	"v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";44 45#define EI_SHIFT(x)	(ei_local->reg_offset[x])46#define ei_inb(port)	in_8(port)47#define ei_outb(val, port)	out_8(port, val)48#define ei_inb_p(port)	in_8(port)49#define ei_outb_p(val, port)	out_8(port, val)50 51#include "lib8390.c"52 53#define WD_START_PG			0x00	/* First page of TX buffer */54#define CABLETRON_RX_START_PG		0x00    /* First page of RX buffer */55#define CABLETRON_RX_STOP_PG		0x30    /* Last page +1 of RX ring */56#define CABLETRON_TX_START_PG		CABLETRON_RX_STOP_PG57						/* First page of TX buffer */58 59/*60 * Unfortunately it seems we have to hardcode these for the moment61 * Shouldn't the card know about this?62 * Does anyone know where to read it off the card?63 * Do we trust the data provided by the card?64 */65 66#define DAYNA_8390_BASE		0x8000067#define DAYNA_8390_MEM		0x0000068 69#define CABLETRON_8390_BASE	0x9000070#define CABLETRON_8390_MEM	0x0000071 72#define INTERLAN_8390_BASE	0xE000073#define INTERLAN_8390_MEM	0xD000074 75enum mac8390_type {76	MAC8390_NONE = -1,77	MAC8390_APPLE,78	MAC8390_ASANTE,79	MAC8390_FARALLON,80	MAC8390_CABLETRON,81	MAC8390_DAYNA,82	MAC8390_INTERLAN,83	MAC8390_KINETICS,84};85 86static const char *cardname[] = {87	"apple",88	"asante",89	"farallon",90	"cabletron",91	"dayna",92	"interlan",93	"kinetics",94};95 96static const int word16[] = {97	1, /* apple */98	1, /* asante */99	1, /* farallon */100	1, /* cabletron */101	0, /* dayna */102	1, /* interlan */103	0, /* kinetics */104};105 106/* on which cards do we use NuBus resources? */107static const int useresources[] = {108	1, /* apple */109	1, /* asante */110	1, /* farallon */111	0, /* cabletron */112	0, /* dayna */113	0, /* interlan */114	0, /* kinetics */115};116 117enum mac8390_access {118	ACCESS_UNKNOWN = 0,119	ACCESS_32,120	ACCESS_16,121};122 123extern int mac8390_memtest(struct net_device *dev);124static int mac8390_initdev(struct net_device *dev, struct nubus_board *board,125			   enum mac8390_type type);126 127static int mac8390_open(struct net_device *dev);128static int mac8390_close(struct net_device *dev);129static void mac8390_no_reset(struct net_device *dev);130static void interlan_reset(struct net_device *dev);131 132/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/133static void sane_get_8390_hdr(struct net_device *dev,134			      struct e8390_pkt_hdr *hdr, int ring_page);135static void sane_block_input(struct net_device *dev, int count,136			     struct sk_buff *skb, int ring_offset);137static void sane_block_output(struct net_device *dev, int count,138			      const unsigned char *buf, const int start_page);139 140/* dayna_memcpy to and from card */141static void dayna_memcpy_fromcard(struct net_device *dev, void *to,142				int from, int count);143static void dayna_memcpy_tocard(struct net_device *dev, int to,144			      const void *from, int count);145 146/* Dayna - Dayna/Kinetics use this */147static void dayna_get_8390_hdr(struct net_device *dev,148			       struct e8390_pkt_hdr *hdr, int ring_page);149static void dayna_block_input(struct net_device *dev, int count,150			      struct sk_buff *skb, int ring_offset);151static void dayna_block_output(struct net_device *dev, int count,152			       const unsigned char *buf, int start_page);153 154/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */155static void slow_sane_get_8390_hdr(struct net_device *dev,156				   struct e8390_pkt_hdr *hdr, int ring_page);157static void slow_sane_block_input(struct net_device *dev, int count,158				  struct sk_buff *skb, int ring_offset);159static void slow_sane_block_output(struct net_device *dev, int count,160				   const unsigned char *buf, int start_page);161static void word_memcpy_tocard(unsigned long tp, const void *fp, int count);162static void word_memcpy_fromcard(void *tp, unsigned long fp, int count);163 164static enum mac8390_type mac8390_ident(struct nubus_rsrc *fres)165{166	switch (fres->dr_sw) {167	case NUBUS_DRSW_3COM:168		switch (fres->dr_hw) {169		case NUBUS_DRHW_APPLE_SONIC_NB:170		case NUBUS_DRHW_APPLE_SONIC_LC:171		case NUBUS_DRHW_SONNET:172			return MAC8390_NONE;173		default:174			return MAC8390_APPLE;175		}176 177	case NUBUS_DRSW_APPLE:178		switch (fres->dr_hw) {179		case NUBUS_DRHW_ASANTE_LC:180			return MAC8390_NONE;181		case NUBUS_DRHW_CABLETRON:182			return MAC8390_CABLETRON;183		default:184			return MAC8390_APPLE;185		}186 187	case NUBUS_DRSW_ASANTE:188		return MAC8390_ASANTE;189 190	case NUBUS_DRSW_TECHWORKS:191	case NUBUS_DRSW_DAYNA2:192	case NUBUS_DRSW_DAYNA_LC:193		if (fres->dr_hw == NUBUS_DRHW_CABLETRON)194			return MAC8390_CABLETRON;195		else196			return MAC8390_APPLE;197 198	case NUBUS_DRSW_FARALLON:199		return MAC8390_FARALLON;200 201	case NUBUS_DRSW_KINETICS:202		switch (fres->dr_hw) {203		case NUBUS_DRHW_INTERLAN:204			return MAC8390_INTERLAN;205		default:206			return MAC8390_KINETICS;207		}208 209	case NUBUS_DRSW_DAYNA:210		/*211		 * These correspond to Dayna Sonic cards212		 * which use the macsonic driver213		 */214		if (fres->dr_hw == NUBUS_DRHW_SMC9194 ||215		    fres->dr_hw == NUBUS_DRHW_INTERLAN)216			return MAC8390_NONE;217		else218			return MAC8390_DAYNA;219	}220	return MAC8390_NONE;221}222 223static enum mac8390_access mac8390_testio(unsigned long membase)224{225	u32 outdata = 0xA5A0B5B0;226	u32 indata = 0;227 228	/* Try writing 32 bits */229	nubus_writel(outdata, membase);230	/* Now read it back */231	indata = nubus_readl(membase);232	if (outdata == indata)233		return ACCESS_32;234 235	outdata = 0xC5C0D5D0;236	indata = 0;237 238	/* Write 16 bit output */239	word_memcpy_tocard(membase, &outdata, 4);240	/* Now read it back */241	word_memcpy_fromcard(&indata, membase, 4);242	if (outdata == indata)243		return ACCESS_16;244 245	return ACCESS_UNKNOWN;246}247 248static int mac8390_memsize(unsigned long membase)249{250	unsigned long flags;251	int i, j;252 253	local_irq_save(flags);254	/* Check up to 32K in 4K increments */255	for (i = 0; i < 8; i++) {256		volatile unsigned short *m = (unsigned short *)(membase + (i * 0x1000));257 258		/* Unwriteable - we have a fully decoded card and the259		   RAM end located */260		if (hwreg_present(m) == 0)261			break;262 263		/* write a distinctive byte */264		*m = 0xA5A0 | i;265		/* check that we read back what we wrote */266		if (*m != (0xA5A0 | i))267			break;268 269		/* check for partial decode and wrap */270		for (j = 0; j < i; j++) {271			volatile unsigned short *p = (unsigned short *)(membase + (j * 0x1000));272			if (*p != (0xA5A0 | j))273				break;274		}275	}276	local_irq_restore(flags);277	/*278	 * in any case, we stopped once we tried one block too many,279	 * or once we reached 32K280	 */281	return i * 0x1000;282}283 284static bool mac8390_rsrc_init(struct net_device *dev,285			      struct nubus_rsrc *fres,286			      enum mac8390_type cardtype)287{288	struct nubus_board *board = fres->board;289	struct nubus_dir dir;290	struct nubus_dirent ent;291	int offset;292	volatile unsigned short *i;293	u8 addr[ETH_ALEN];294 295	dev->irq = SLOT2IRQ(board->slot);296	/* This is getting to be a habit */297	dev->base_addr = board->slot_addr | ((board->slot & 0xf) << 20);298 299	/*300	 * Get some Nubus info - we will trust the card's idea301	 * of where its memory and registers are.302	 */303 304	if (nubus_get_func_dir(fres, &dir) == -1) {305		dev_err(&board->dev,306			"Unable to get Nubus functional directory\n");307		return false;308	}309 310	/* Get the MAC address */311	if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) {312		dev_info(&board->dev, "MAC address resource not found\n");313		return false;314	}315 316	nubus_get_rsrc_mem(addr, &ent, 6);317	eth_hw_addr_set(dev, addr);318 319	if (useresources[cardtype] == 1) {320		nubus_rewinddir(&dir);321		if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS,322				    &ent) == -1) {323			dev_err(&board->dev,324				"Memory offset resource not found\n");325			return false;326		}327		nubus_get_rsrc_mem(&offset, &ent, 4);328		dev->mem_start = dev->base_addr + offset;329		/* yes, this is how the Apple driver does it */330		dev->base_addr = dev->mem_start + 0x10000;331		nubus_rewinddir(&dir);332		if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH,333				    &ent) == -1) {334			dev_info(&board->dev,335				 "Memory length resource not found, probing\n");336			offset = mac8390_memsize(dev->mem_start);337		} else {338			nubus_get_rsrc_mem(&offset, &ent, 4);339		}340		dev->mem_end = dev->mem_start + offset;341	} else {342		switch (cardtype) {343		case MAC8390_KINETICS:344		case MAC8390_DAYNA: /* it's the same */345			dev->base_addr = (int)(board->slot_addr +346					       DAYNA_8390_BASE);347			dev->mem_start = (int)(board->slot_addr +348					       DAYNA_8390_MEM);349			dev->mem_end = dev->mem_start +350				       mac8390_memsize(dev->mem_start);351			break;352		case MAC8390_INTERLAN:353			dev->base_addr = (int)(board->slot_addr +354					       INTERLAN_8390_BASE);355			dev->mem_start = (int)(board->slot_addr +356					       INTERLAN_8390_MEM);357			dev->mem_end = dev->mem_start +358				       mac8390_memsize(dev->mem_start);359			break;360		case MAC8390_CABLETRON:361			dev->base_addr = (int)(board->slot_addr +362					       CABLETRON_8390_BASE);363			dev->mem_start = (int)(board->slot_addr +364					       CABLETRON_8390_MEM);365			/* The base address is unreadable if 0x00366			 * has been written to the command register367			 * Reset the chip by writing E8390_NODMA +368			 *   E8390_PAGE0 + E8390_STOP just to be369			 *   sure370			 */371			i = (void *)dev->base_addr;372			*i = 0x21;373			dev->mem_end = dev->mem_start +374				       mac8390_memsize(dev->mem_start);375			break;376 377		default:378			dev_err(&board->dev,379				"No known base address for card type\n");380			return false;381		}382	}383 384	return true;385}386 387static int mac8390_device_probe(struct nubus_board *board)388{389	struct net_device *dev;390	int err = -ENODEV;391	struct nubus_rsrc *fres;392	enum mac8390_type cardtype = MAC8390_NONE;393 394	dev = ____alloc_ei_netdev(0);395	if (!dev)396		return -ENOMEM;397 398	SET_NETDEV_DEV(dev, &board->dev);399 400	for_each_board_func_rsrc(board, fres) {401		if (fres->category != NUBUS_CAT_NETWORK ||402		    fres->type != NUBUS_TYPE_ETHERNET)403			continue;404 405		cardtype = mac8390_ident(fres);406		if (cardtype == MAC8390_NONE)407			continue;408 409		if (mac8390_rsrc_init(dev, fres, cardtype))410			break;411	}412	if (!fres)413		goto out;414 415	err = mac8390_initdev(dev, board, cardtype);416	if (err)417		goto out;418 419	err = register_netdev(dev);420	if (err)421		goto out;422 423	nubus_set_drvdata(board, dev);424	return 0;425 426out:427	free_netdev(dev);428	return err;429}430 431static void mac8390_device_remove(struct nubus_board *board)432{433	struct net_device *dev = nubus_get_drvdata(board);434 435	unregister_netdev(dev);436	free_netdev(dev);437}438 439static struct nubus_driver mac8390_driver = {440	.probe = mac8390_device_probe,441	.remove = mac8390_device_remove,442	.driver = {443		.name = KBUILD_MODNAME,444		.owner = THIS_MODULE,445	}446};447 448MODULE_AUTHOR("David Huggins-Daines <dhd@debian.org> and others");449MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver");450MODULE_LICENSE("GPL");451 452static int __init mac8390_init(void)453{454	return nubus_driver_register(&mac8390_driver);455}456module_init(mac8390_init);457 458static void __exit mac8390_exit(void)459{460	nubus_driver_unregister(&mac8390_driver);461}462module_exit(mac8390_exit);463 464static const struct net_device_ops mac8390_netdev_ops = {465	.ndo_open 		= mac8390_open,466	.ndo_stop		= mac8390_close,467	.ndo_start_xmit		= __ei_start_xmit,468	.ndo_tx_timeout		= __ei_tx_timeout,469	.ndo_get_stats		= __ei_get_stats,470	.ndo_set_rx_mode	= __ei_set_multicast_list,471	.ndo_validate_addr	= eth_validate_addr,472	.ndo_set_mac_address 	= eth_mac_addr,473#ifdef CONFIG_NET_POLL_CONTROLLER474	.ndo_poll_controller	= __ei_poll,475#endif476};477 478static int mac8390_initdev(struct net_device *dev, struct nubus_board *board,479			   enum mac8390_type type)480{481	static u32 fwrd4_offsets[16] = {482		0,      4,      8,      12,483		16,     20,     24,     28,484		32,     36,     40,     44,485		48,     52,     56,     60486	};487	static u32 back4_offsets[16] = {488		60,     56,     52,     48,489		44,     40,     36,     32,490		28,     24,     20,     16,491		12,     8,      4,      0492	};493	static u32 fwrd2_offsets[16] = {494		0,      2,      4,      6,495		8,     10,     12,     14,496		16,    18,     20,     22,497		24,    26,     28,     30498	};499 500	int access_bitmode = 0;501 502	/* Now fill in our stuff */503	dev->netdev_ops = &mac8390_netdev_ops;504 505	/* GAR, ei_status is actually a macro even though it looks global */506	ei_status.name = cardname[type];507	ei_status.word16 = word16[type];508 509	/* Cabletron's TX/RX buffers are backwards */510	if (type == MAC8390_CABLETRON) {511		ei_status.tx_start_page = CABLETRON_TX_START_PG;512		ei_status.rx_start_page = CABLETRON_RX_START_PG;513		ei_status.stop_page = CABLETRON_RX_STOP_PG;514		ei_status.rmem_start = dev->mem_start;515		ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;516	} else {517		ei_status.tx_start_page = WD_START_PG;518		ei_status.rx_start_page = WD_START_PG + TX_PAGES;519		ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;520		ei_status.rmem_start = dev->mem_start + TX_PAGES*256;521		ei_status.rmem_end = dev->mem_end;522	}523 524	/* Fill in model-specific information and functions */525	switch (type) {526	case MAC8390_FARALLON:527	case MAC8390_APPLE:528		switch (mac8390_testio(dev->mem_start)) {529		case ACCESS_UNKNOWN:530			dev_err(&board->dev,531				"Don't know how to access card memory\n");532			return -ENODEV;533 534		case ACCESS_16:535			/* 16 bit card, register map is reversed */536			ei_status.reset_8390 = mac8390_no_reset;537			ei_status.block_input = slow_sane_block_input;538			ei_status.block_output = slow_sane_block_output;539			ei_status.get_8390_hdr = slow_sane_get_8390_hdr;540			ei_status.reg_offset = back4_offsets;541			break;542 543		case ACCESS_32:544			/* 32 bit card, register map is reversed */545			ei_status.reset_8390 = mac8390_no_reset;546			ei_status.block_input = sane_block_input;547			ei_status.block_output = sane_block_output;548			ei_status.get_8390_hdr = sane_get_8390_hdr;549			ei_status.reg_offset = back4_offsets;550			access_bitmode = 1;551			break;552		}553		break;554 555	case MAC8390_ASANTE:556		/* Some Asante cards pass the 32 bit test557		 * but overwrite system memory when run at 32 bit.558		 * so we run them all at 16 bit.559		 */560		ei_status.reset_8390 = mac8390_no_reset;561		ei_status.block_input = slow_sane_block_input;562		ei_status.block_output = slow_sane_block_output;563		ei_status.get_8390_hdr = slow_sane_get_8390_hdr;564		ei_status.reg_offset = back4_offsets;565		break;566 567	case MAC8390_CABLETRON:568		/* 16 bit card, register map is short forward */569		ei_status.reset_8390 = mac8390_no_reset;570		ei_status.block_input = slow_sane_block_input;571		ei_status.block_output = slow_sane_block_output;572		ei_status.get_8390_hdr = slow_sane_get_8390_hdr;573		ei_status.reg_offset = fwrd2_offsets;574		break;575 576	case MAC8390_DAYNA:577	case MAC8390_KINETICS:578		/* 16 bit memory, register map is forward */579		/* dayna and similar */580		ei_status.reset_8390 = mac8390_no_reset;581		ei_status.block_input = dayna_block_input;582		ei_status.block_output = dayna_block_output;583		ei_status.get_8390_hdr = dayna_get_8390_hdr;584		ei_status.reg_offset = fwrd4_offsets;585		break;586 587	case MAC8390_INTERLAN:588		/* 16 bit memory, register map is forward */589		ei_status.reset_8390 = interlan_reset;590		ei_status.block_input = slow_sane_block_input;591		ei_status.block_output = slow_sane_block_output;592		ei_status.get_8390_hdr = slow_sane_get_8390_hdr;593		ei_status.reg_offset = fwrd4_offsets;594		break;595 596	default:597		dev_err(&board->dev, "Unsupported card type\n");598		return -ENODEV;599	}600 601	__NS8390_init(dev, 0);602 603	/* Good, done, now spit out some messages */604	dev_info(&board->dev, "%s (type %s)\n", board->name, cardname[type]);605	dev_info(&board->dev, "MAC %pM, IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",606		 dev->dev_addr, dev->irq,607		 (unsigned int)(dev->mem_end - dev->mem_start) >> 10,608		 dev->mem_start, access_bitmode ? 32 : 16);609	return 0;610}611 612static int mac8390_open(struct net_device *dev)613{614	int err;615 616	__ei_open(dev);617	err = request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev);618	if (err)619		pr_err("%s: unable to get IRQ %d\n", dev->name, dev->irq);620	return err;621}622 623static int mac8390_close(struct net_device *dev)624{625	free_irq(dev->irq, dev);626	__ei_close(dev);627	return 0;628}629 630static void mac8390_no_reset(struct net_device *dev)631{632	struct ei_device *ei_local = netdev_priv(dev);633 634	ei_status.txing = 0;635	netif_info(ei_local, hw, dev, "reset not supported\n");636}637 638static void interlan_reset(struct net_device *dev)639{640	unsigned char *target = nubus_slot_addr(IRQ2SLOT(dev->irq));641	struct ei_device *ei_local = netdev_priv(dev);642 643	netif_info(ei_local, hw, dev, "Need to reset the NS8390 t=%lu...",644		   jiffies);645	ei_status.txing = 0;646	target[0xC0000] = 0;647	if (netif_msg_hw(ei_local))648		pr_cont("reset complete\n");649}650 651/* dayna_memcpy_fromio/dayna_memcpy_toio */652/* directly from daynaport.c by Alan Cox */653static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from,654				  int count)655{656	volatile unsigned char *ptr;657	unsigned char *target = to;658	from <<= 1;	/* word, skip overhead */659	ptr = (unsigned char *)(dev->mem_start+from);660	/* Leading byte? */661	if (from & 2) {662		*target++ = ptr[-1];663		ptr += 2;664		count--;665	}666	while (count >= 2) {667		*(unsigned short *)target = *(unsigned short volatile *)ptr;668		ptr += 4;			/* skip cruft */669		target += 2;670		count -= 2;671	}672	/* Trailing byte? */673	if (count)674		*target = *ptr;675}676 677static void dayna_memcpy_tocard(struct net_device *dev, int to,678				const void *from, int count)679{680	volatile unsigned short *ptr;681	const unsigned char *src = from;682	to <<= 1;	/* word, skip overhead */683	ptr = (unsigned short *)(dev->mem_start+to);684	/* Leading byte? */685	if (to & 2) {		/* avoid a byte write (stomps on other data) */686		ptr[-1] = (ptr[-1]&0xFF00)|*src++;687		ptr++;688		count--;689	}690	while (count >= 2) {691		*ptr++ = *(unsigned short *)src;	/* Copy and */692		ptr++;			/* skip cruft */693		src += 2;694		count -= 2;695	}696	/* Trailing byte? */697	if (count) {698		/* card doesn't like byte writes */699		*ptr = (*ptr & 0x00FF) | (*src << 8);700	}701}702 703/* sane block input/output */704static void sane_get_8390_hdr(struct net_device *dev,705			      struct e8390_pkt_hdr *hdr, int ring_page)706{707	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;708	memcpy_fromio(hdr, (void __iomem *)dev->mem_start + hdr_start, 4);709	/* Fix endianness */710	hdr->count = swab16(hdr->count);711}712 713static void sane_block_input(struct net_device *dev, int count,714			     struct sk_buff *skb, int ring_offset)715{716	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);717	unsigned long xfer_start = xfer_base + dev->mem_start;718 719	if (xfer_start + count > ei_status.rmem_end) {720		/* We must wrap the input move. */721		int semi_count = ei_status.rmem_end - xfer_start;722		memcpy_fromio(skb->data,723			      (void __iomem *)dev->mem_start + xfer_base,724			      semi_count);725		count -= semi_count;726		memcpy_fromio(skb->data + semi_count,727			      (void __iomem *)ei_status.rmem_start, count);728	} else {729		memcpy_fromio(skb->data,730			      (void __iomem *)dev->mem_start + xfer_base,731			      count);732	}733}734 735static void sane_block_output(struct net_device *dev, int count,736			      const unsigned char *buf, int start_page)737{738	long shmem = (start_page - WD_START_PG)<<8;739 740	memcpy_toio((void __iomem *)dev->mem_start + shmem, buf, count);741}742 743/* dayna block input/output */744static void dayna_get_8390_hdr(struct net_device *dev,745			       struct e8390_pkt_hdr *hdr, int ring_page)746{747	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;748 749	dayna_memcpy_fromcard(dev, hdr, hdr_start, 4);750	/* Fix endianness */751	hdr->count = (hdr->count & 0xFF) << 8 | (hdr->count >> 8);752}753 754static void dayna_block_input(struct net_device *dev, int count,755			      struct sk_buff *skb, int ring_offset)756{757	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);758	unsigned long xfer_start = xfer_base+dev->mem_start;759 760	/* Note the offset math is done in card memory space which is word761	   per long onto our space. */762 763	if (xfer_start + count > ei_status.rmem_end) {764		/* We must wrap the input move. */765		int semi_count = ei_status.rmem_end - xfer_start;766		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);767		count -= semi_count;768		dayna_memcpy_fromcard(dev, skb->data + semi_count,769				      ei_status.rmem_start - dev->mem_start,770				      count);771	} else {772		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);773	}774}775 776static void dayna_block_output(struct net_device *dev, int count,777			       const unsigned char *buf,778			       int start_page)779{780	long shmem = (start_page - WD_START_PG)<<8;781 782	dayna_memcpy_tocard(dev, shmem, buf, count);783}784 785/* Cabletron block I/O */786static void slow_sane_get_8390_hdr(struct net_device *dev,787				   struct e8390_pkt_hdr *hdr,788				   int ring_page)789{790	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;791	word_memcpy_fromcard(hdr, dev->mem_start + hdr_start, 4);792	/* Register endianism - fix here rather than 8390.c */793	hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);794}795 796static void slow_sane_block_input(struct net_device *dev, int count,797				  struct sk_buff *skb, int ring_offset)798{799	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);800	unsigned long xfer_start = xfer_base+dev->mem_start;801 802	if (xfer_start + count > ei_status.rmem_end) {803		/* We must wrap the input move. */804		int semi_count = ei_status.rmem_end - xfer_start;805		word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,806				     semi_count);807		count -= semi_count;808		word_memcpy_fromcard(skb->data + semi_count,809				     ei_status.rmem_start, count);810	} else {811		word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,812				     count);813	}814}815 816static void slow_sane_block_output(struct net_device *dev, int count,817				   const unsigned char *buf, int start_page)818{819	long shmem = (start_page - WD_START_PG)<<8;820 821	word_memcpy_tocard(dev->mem_start + shmem, buf, count);822}823 824static void word_memcpy_tocard(unsigned long tp, const void *fp, int count)825{826	volatile unsigned short *to = (void *)tp;827	const unsigned short *from = fp;828 829	count++;830	count /= 2;831 832	while (count--)833		*to++ = *from++;834}835 836static void word_memcpy_fromcard(void *tp, unsigned long fp, int count)837{838	unsigned short *to = tp;839	const volatile unsigned short *from = (const void *)fp;840 841	count++;842	count /= 2;843 844	while (count--)845		*to++ = *from++;846}847 848 849