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