diff options
Diffstat (limited to 'i386/i386at/gpl/if_hpp.c')
-rw-r--r-- | i386/i386at/gpl/if_hpp.c | 690 |
1 files changed, 0 insertions, 690 deletions
diff --git a/i386/i386at/gpl/if_hpp.c b/i386/i386at/gpl/if_hpp.c deleted file mode 100644 index c177030..0000000 --- a/i386/i386at/gpl/if_hpp.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - Written 1994 by Donald Becker. - - This driver is for the Hewlett Packard PC LAN (27***) plus ethercards. - These cards are sold under several model numbers, usually 2724*. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - As is often the case, a great deal of credit is owed to Russ Nelson. - The Crynwr packet driver was my primary source of HP-specific - programming information. -*/ - -/* - * Ported to mach by Stephen Clawson, sclawson@cs.utah.edu - * University of Utah CSL. - * - * Derived from the Linux driver by Donald Becker. - * - * Also uses code Shantanu Goel adapted from Donald Becker - * for ns8930 support. - * - */ - -#include <hpp.h> -#if NHPP > 0 - -#include <sys/types.h> -#include "vm_param.h" -#include <kern/time_out.h> -#include <device/device_types.h> -#include <device/errno.h> -#include <device/io_req.h> -#include <device/if_hdr.h> -#include <device/if_ether.h> -#include <device/net_status.h> -#include <device/net_io.h> -#include <chips/busses.h> -#include <i386/ipl.h> -#include <i386/pio.h> -#include <i386at/gpl/if_nsreg.h> - - -/* - * XXX - This is some gross glue garbage. The io instructions really - * should be integrated into pio.h... - */ -#define IO_DELAY __asm__ __volatile__("outb %al,$0x80") -#define outb_p(p, v) { outb(p, v); IO_DELAY; } -#define inb_p(p) ({ unsigned char _v; _v = inb(p); IO_DELAY; _v; }) - - -static __inline void -insw(u_short port, void *addr, int cnt) -{ - __asm __volatile("cld\n\trepne\n\tinsw" : - : "d" (port), "D" (addr), "c" (cnt) : "%edi", "%ecx"); -} - -static __inline void -outsw(u_short port, void *addr, int cnt) -{ - __asm __volatile("cld\n\trepne\n\toutsw" : - : "d" (port), "S" (addr), "c" (cnt) : "%esi", "%ecx"); -} - - -/* - The HP EtherTwist chip implementation is a fairly routine DP8390 - implementation. It allows both shared memory and programmed-I/O buffer - access, using a custom interface for both. The programmed-I/O mode is - entirely implemented in the HP EtherTwist chip, bypassing the problem - ridden built-in 8390 facilities used on NE2000 designs. The shared - memory mode is likewise special, with an offset register used to make - packets appear at the shared memory base. Both modes use a base and bounds - page register to hide the Rx ring buffer wrap -- a packet that spans the - end of physical buffer memory appears continuous to the driver. (c.f. the - 3c503 and Cabletron E2100) - - A special note: the internal buffer of the board is only 8 bits wide. - This lays several nasty traps for the unaware: - - the 8390 must be programmed for byte-wide operations - - all I/O and memory operations must work on whole words (the access - latches are serially preloaded and have no byte-swapping ability). - - This board is laid out in I/O space much like the earlier HP boards: - the first 16 locations are for the board registers, and the second 16 are - for the 8390. The board is easy to identify, with both a dedicated 16 bit - ID register and a constant 0x530* value in the upper bits of the paging - register. -*/ - -#define HP_ID 0x00 /* ID register, always 0x4850. */ -#define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */ -#define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option.*/ -#define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page.*/ -#define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page.*/ -#define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page.*/ -#define HPP_NIC_OFFSET 0x10 /* Offset to the 8390 registers.*/ -#define HP_IO_EXTENT 32 - -#define HP_START_PG 0x00 /* First page of TX buffer */ -#define HP_STOP_PG 0x80 /* Last page +1 of RX ring */ -/*#define HP_STOP_PG 0x1f - -/* The register set selected in HP_PAGING. */ -enum PageName { - Perf_Page = 0, /* Normal operation. */ - MAC_Page = 1, /* The ethernet address (+checksum). */ - HW_Page = 2, /* EEPROM-loaded hw parameters. */ - LAN_Page = 4, /* Transciever type, testing, etc. */ - ID_Page = 6 }; - -/* The bit definitions for the HPP_OPTION register. */ -enum HP_Option { - NICReset = 1, /* Active low, really UNreset. */ - ChipReset = 2, - EnableIRQ = 4, - FakeIntr = 8, - BootROMEnb = 0x10, - IOEnb = 0x20, - MemEnable = 0x40, - ZeroWait = 0x80, - MemDisable = 0x1000, }; - - -void hpp_reset_8390(struct nssoftc *ns); - -void hpp_mem_block_input(struct nssoftc *ns, int, char *, int); -int hpp_mem_block_output(struct nssoftc *ns, int, char *, int); -void hpp_io_block_input(struct nssoftc *ns, int, char *, int); -int hpp_io_block_output(struct nssoftc *ns, int,char *, int); - - -/* - * Watchdog timer. - */ -int hppwstart = 0; -void hppwatch(void); - - -/* - * Autoconfig structures. - */ -int hpp_std[] = { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0 }; -struct bus_device *hpp_info[NHPP]; -int hpp_probe(); -void hpp_attach(); -struct bus_driver hppdriver = { - hpp_probe, 0, hpp_attach, 0, hpp_std, "hpp", hpp_info, 0, 0, 0 -}; - - -/* - * ns8390 state. - */ -struct nssoftc hppnssoftc[NHPP]; - - -/* - * hpp state. - */ -struct hppsoftc { - unsigned long rmem_start; /* shmem "recv" start */ - unsigned long rmem_end; /* shmem "recv" end */ - unsigned long mem_start; /* shared mem start */ - unsigned long mem_end; /* shared mem end */ -} hppsoftc[NHPP]; - - -/* - * Probe a list of addresses for the card. - * - */ -int hpp_probe(port, dev) - int port; - struct bus_device *dev; -{ - int unit = dev->unit; - char *str = "hp-plus ethernet board %d out of range.\n"; - caddr_t base = (caddr_t) (dev ? dev->address : 0); - int i; - - if ((unit < 0) || (unit >= NHPP)) { - printf(str, unit); - return(0); - } - - /* Check a single specified location. */ - if (base > (caddr_t) 0x1ff) - return hpp_probe1(dev, base); - else if (base != 0) /* Don't probe at all. */ - return 0; - - for (i = 0; hpp_std[i]; i++) { - int ioaddr = hpp_std[i]; - - if ( ioaddr > 0 && hpp_probe1(dev, ioaddr) ) { - dev->address = ioaddr; - hpp_std[i] = -1; /* Mark address used */ - return(1); - } - } - - return 0; -} - - - -/* - * Do the interesting part of the probe at a single address. - * - */ -int hpp_probe1(dev, ioaddr) - struct bus_device *dev; - int ioaddr; -{ - int i; - u_char checksum = 0; - int mem_start; - - struct hppsoftc *hpp = &hppsoftc[dev->unit]; - struct nssoftc *ns = &hppnssoftc[dev->unit]; - struct ifnet *ifp = &ns->sc_if; - - /* Check for the HP+ signature, 50 48 0x 53. */ - if (inw(ioaddr + HP_ID) != 0x4850 - || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) - return 0; - - - printf("%s%d: HP PClan plus at %#3x,", dev->name, dev->unit, ioaddr); - /* Retrieve and checksum the station address. */ - outw(ioaddr + HP_PAGING, MAC_Page); - - printf("MAC_Page = %d, ioaddr = %x\n", MAC_Page, ioaddr); - - for(i = 0; i < ETHER_ADDR_LEN; i++) { - u_char inval = inb(ioaddr + 8 + i); - ns->sc_addr[i] = inval; - checksum += inval; - printf(" %2.2x", inval); - } - checksum += inb(ioaddr + 14); - - if (checksum != 0xff) { - printf(" bad checksum %2.2x.\n", checksum); - return 0; - } else { - /* Point at the Software Configuration Flags. */ - outw(ioaddr + HP_PAGING, ID_Page); - printf(" ID %4.4x", inw(ioaddr + 12)); - } - - - /* Read the IRQ line. */ - outw(ioaddr + HP_PAGING, HW_Page); - { - int irq = inb(ioaddr + 13) & 0x0f; - int option = inw(ioaddr + HPP_OPTION); - - dev->sysdep1 = irq; - take_dev_irq(dev); - - if (option & MemEnable) { - mem_start = inw(ioaddr + 9) << 8; - printf(", IRQ %d, memory address %#x.\n", irq, mem_start); - } else { - mem_start = 0; - printf(", IRQ %d, programmed-I/O mode.\n", irq); - } - } - - /* Set the wrap registers for string I/O reads. */ - outw( ioaddr + 14, (HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8)); - - /* Set the base address to point to the NIC, not the "real" base! */ - ns->sc_port = ioaddr + HPP_NIC_OFFSET; - - ns->sc_name = dev->name; - ns->sc_unit = dev->unit; - ns->sc_pingpong = 0; /* turn off pingpong mode */ - ns->sc_word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ - ns->sc_txstrtpg = HP_START_PG; - ns->sc_rxstrtpg = HP_START_PG + TX_2X_PAGES; - ns->sc_stoppg = HP_STOP_PG; - - - ns->sc_reset = hpp_reset_8390; - ns->sc_input = hpp_io_block_input; - ns->sc_output = hpp_io_block_output; - - /* Check if the memory_enable flag is set in the option register. */ - if (mem_start) { - ns->sc_input = hpp_mem_block_input; - ns->sc_output = hpp_mem_block_output; - hpp->mem_start = mem_start; - hpp->rmem_start = hpp->mem_start + TX_2X_PAGES * 256; - hpp->mem_end = hpp->rmem_end - = hpp->mem_start + (HP_STOP_PG - HP_START_PG) * 256; - } - - outw(ioaddr + HP_PAGING, Perf_Page); - - /* Leave the 8390 and HP chip reset. */ - outw( ioaddr + HPP_OPTION, inw(ioaddr + HPP_OPTION) & ~EnableIRQ ); - - /* - * Initialize interface header. - */ - ifp->if_unit = dev->unit; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST; - ifp->if_header_size = sizeof(struct ether_header); - ifp->if_header_format = HDR_ETHERNET; - ifp->if_address_size = ETHER_ADDR_LEN; - ifp->if_address = ns->sc_addr; - if_init_queues(ifp); - - return (1); -} - -/* - * XXX - * - * this routine really should do the invasive part of the setup. - */ -void -hpp_attach(dev) - struct bus_device *dev; -{ - /* NULL */ -} - - - -int -hppopen(dev, flag) - dev_t dev; - int flag; -{ - int s, unit = minor(dev); - struct bus_device *bd; - struct hppsoftc *hpp; - struct nssoftc *ns = &hppnssoftc[unit]; - - int ioaddr = ns->sc_port - HPP_NIC_OFFSET; - int option_reg; - - if (unit < 0 || unit >= NHPP || - (bd = hpp_info[unit]) == 0 || !(bd->alive)) - return ENXIO; - - /* - * Start watchdog. - */ - if (!hppwstart) { - hppwstart++; - timeout(hppwatch, 0, hz); - } - hpp = &hppsoftc[unit]; - ns->sc_if.if_flags |= IFF_UP; - - s = splimp(); - - /* Reset the 8390 and HP chip. */ - option_reg = inw(ioaddr + HPP_OPTION); - outw( ioaddr + HPP_OPTION, option_reg & ~(NICReset + ChipReset) ); - IO_DELAY; IO_DELAY; - - /* Unreset the board and enable interrupts. */ - outw( ioaddr + HPP_OPTION, option_reg | (EnableIRQ + NICReset + ChipReset)); - - /* Set the wrap registers for programmed-I/O operation. */ - outw( ioaddr + HP_PAGING, HW_Page ); - outw( ioaddr + 14, (HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8) ); - - /* Select the operational page. */ - outw( ioaddr + HP_PAGING, Perf_Page ); - nsinit(ns); - - splx(s); - - return (0); -} - -/* - * needs to be called at splimp()? - * - */ -void -hpp_reset_8390(ns) - struct nssoftc *ns; -{ - int ioaddr = ns->sc_port - HPP_NIC_OFFSET; - int option_reg = inw(ioaddr + HPP_OPTION); - - outw( ioaddr + HPP_OPTION, option_reg & ~(NICReset + ChipReset) ); - /* Pause a few cycles for the hardware reset to take place. */ - IO_DELAY; - IO_DELAY; - ns->sc_txing = 0; - outw( ioaddr + HPP_OPTION, option_reg | (EnableIRQ + NICReset + ChipReset) ); - - /* - * XXX - I'm not sure there needs to be this many IO_DELAY's... - */ - IO_DELAY; IO_DELAY; - IO_DELAY; IO_DELAY; - - if ((inb_p(ioaddr + HPP_NIC_OFFSET + EN0_ISR) & ENISR_RESET) == 0) - printf("%s: hp_reset_8390() did not complete.\n", ns->sc_name); - - return; -} - - -/* - * Block input and output, similar to the Crynwr packet driver. - * Note that transfer with the EtherTwist+ must be on word boundaries. - */ -void -hpp_io_block_input(ns, count, buf, ring_offset) - struct nssoftc *ns; - int count; - char *buf; - int ring_offset; -{ - int ioaddr = ns->sc_port - HPP_NIC_OFFSET; - - outw(ioaddr + HPP_IN_ADDR, ring_offset); - - insw(ioaddr + HP_DATAPORT, buf, count >> 1 ); - - if (count & 0x01) - buf[count-1] = (char) inw(ioaddr + HP_DATAPORT); - -} - -void -hpp_mem_block_input(ns, count, buf, ring_offset) - struct nssoftc *ns; - int count; - char *buf; - int ring_offset; -{ - int ioaddr = ns->sc_port - HPP_NIC_OFFSET; - int option_reg = inw(ioaddr + HPP_OPTION); - char *mem_start = (char *)phystokv(hppsoftc[ns->sc_unit].mem_start); - - outw(ioaddr + HPP_IN_ADDR, ring_offset); - outw(ioaddr + HPP_OPTION, option_reg & ~(MemDisable + BootROMEnb)); - - /* copy as much as we can straight through */ - bcopy16(mem_start, buf, count & ~1); - - /* Now we copy that last byte. */ - if (count & 0x01) { - u_short savebyte[2]; - - bcopy16(mem_start + (count & ~1), savebyte, 2); - buf[count-1] = savebyte[0]; - } - - outw(ioaddr + HPP_OPTION, option_reg); -} - - -/* - * output data into NIC buffers. - * - * NOTE: All transfers must be on word boundaries. - */ -int -hpp_io_block_output(ns, count, buf, start_page) - struct nssoftc *ns; - int count; - char *buf; - int start_page; -{ - int ioaddr = ns->sc_port - HPP_NIC_OFFSET; - - outw(ioaddr + HPP_OUT_ADDR, start_page << 8) ; - - if (count > 1) { - outsw(ioaddr + HP_DATAPORT, buf, count >> 1); - } - - if ( (count & 1) == 1 ) { - u_char savebyte[2]; - - savebyte[1] = 0; - savebyte[0] = buf[count - 1]; - outw(ioaddr + HP_DATAPORT, *(u_short *)savebyte); - } - - if (count < (ETHERMIN + sizeof( struct ether_header ))) - count = ETHERMIN + sizeof( struct ether_header ); - - - return (count) ; -} - - -/* XXX - * - * I take great pains to not try and bcopy past the end of the buffer, - * does this matter? Are the io request buffers the exact byte size? - */ -int -hpp_mem_block_output(ns, count, buf, start_page ) - struct nssoftc *ns; - int count; - char *buf; - int start_page; -{ - int ioaddr = ns->sc_port - HPP_NIC_OFFSET; - int option_reg = inw(ioaddr + HPP_OPTION); - struct hppsoftc *hpp = &hppsoftc[ns->sc_unit]; - char *shmem; - - outw(ioaddr + HPP_OUT_ADDR, start_page << 8); - outw(ioaddr + HPP_OPTION, option_reg & ~(MemDisable + BootROMEnb)); - - shmem = (char *)phystokv(hpp->mem_start); - bcopy16(buf, shmem, count & ~1); - - if ( (count & 1) == 1 ) { - u_char savebyte[2]; - - savebyte[1] = 0; - savebyte[0] = buf[count - 1]; - bcopy16(savebyte, shmem + (count & ~1), 2); - } - - while (count < ETHERMIN + sizeof(struct ether_header)) { - *(shmem + count) = 0; - count++; - } - - outw(ioaddr + HPP_OPTION, option_reg); - - return count; -} - - -int -hppintr(unit) - int unit; -{ - nsintr(&hppnssoftc[unit]); - - return(0); -} - -void -hppstart(unit) - int unit; -{ - nsstart(&hppnssoftc[unit]); -} - -int hppoutput(); - -int -hppoutput(dev, ior) - dev_t dev; - io_req_t ior; -{ - int unit = minor(dev); - struct bus_device *ui; - - if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) - return (ENXIO); - - return (net_write(&hppnssoftc[unit].sc_if, hppstart, ior)); -} - - -int -hppsetinput(dev, receive_port, priority, filter, filter_count) - dev_t dev; - mach_port_t receive_port; - int priority; - filter_t *filter; - unsigned filter_count; -{ - int unit = minor(dev); - struct bus_device *ui; - - if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) - return (ENXIO); - - return (net_set_filter(&hppnssoftc[unit].sc_if, receive_port, - priority, filter, filter_count)); -} - - -int -hppgetstat(dev, flavor, status, count) - dev_t dev; - int flavor; - dev_status_t status; - unsigned *count; -{ - int unit = minor(dev); - struct bus_device *ui; - - if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) - return (ENXIO); - - return (net_getstat(&hppnssoftc[unit].sc_if, flavor, status, count)); -} - - -int -hppsetstat(dev, flavor, status, count) - dev_t dev; - int flavor; - dev_status_t status; - unsigned count; -{ - int unit = minor(dev), oflags, s; - struct bus_device *ui; - struct ifnet *ifp; - struct net_status *ns; - - if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) - return (ENXIO); - - ifp = &hppnssoftc[unit].sc_if; - - switch (flavor) { - - case NET_STATUS: - if (count < NET_STATUS_COUNT) - return (D_INVALID_SIZE); - ns = (struct net_status *)status; - oflags = ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC); - ifp->if_flags &= ~(IFF_ALLMULTI|IFF_PROMISC); - ifp->if_flags |= ns->flags & (IFF_ALLMULTI|IFF_PROMISC); - if ((ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC)) != oflags) { - s = splimp(); - nsinit(&hppnssoftc[unit]); - splx(s); - } - break; - - default: - return (D_INVALID_OPERATION); - } - return (D_SUCCESS); -} - -/* - * Watchdog. - * Check for hung transmissions. - */ -void -hppwatch() -{ - int unit, s; - struct nssoftc *ns; - - timeout(hppwatch, 0, hz); - - s = splimp(); - for (unit = 0; unit < NHPP; unit++) { - if (hpp_info[unit] == 0 || hpp_info[unit]->alive == 0) - continue; - ns = &hppnssoftc[unit]; - if (ns->sc_timer && --ns->sc_timer == 0) { - printf("hpp%d: transmission timeout\n", unit); - (*ns->sc_reset)(ns); - nsinit(ns); - } - } - splx(s); -} - - -#endif /* NHPP > 0 */ - - |