summaryrefslogtreecommitdiffstats
path: root/sys/dev/ed
diff options
context:
space:
mode:
authordg <dg@FreeBSD.org>1996-08-07 11:18:23 +0000
committerdg <dg@FreeBSD.org>1996-08-07 11:18:23 +0000
commit93c92bd9f8c79ded0e9233b67afcb798971b6dd6 (patch)
tree755b9c05a17e56d707b396761d23b1871d9f1c4a /sys/dev/ed
parent8bd2231427bdab6c232fe2d2702663e0c46db1b8 (diff)
downloadFreeBSD-src-93c92bd9f8c79ded0e9233b67afcb798971b6dd6.zip
FreeBSD-src-93c92bd9f8c79ded0e9233b67afcb798971b6dd6.tar.gz
This diff adds support for the HP PC Lan+ cards (model numbers: 27247B
and 27252A) in FreeBSD's `ed' driver. Submitted by: A JOSEPH KOSHY <koshy@india.hp.com>
Diffstat (limited to 'sys/dev/ed')
-rw-r--r--sys/dev/ed/if_ed.c724
-rw-r--r--sys/dev/ed/if_edreg.h86
2 files changed, 778 insertions, 32 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c
index 9418e76..eb78d0b 100644
--- a/sys/dev/ed/if_ed.c
+++ b/sys/dev/ed/if_ed.c
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_ed.c,v 1.102 1996/08/04 10:57:29 phk Exp $
+ * $Id: if_ed.c,v 1.103 1996/08/06 21:14:02 phk Exp $
*/
/*
@@ -108,6 +108,14 @@ struct ed_softc {
int is790; /* set by the probe code if the card is 790
* based */
+/*
+ * HP PC LAN PLUS card support.
+ */
+
+ u_short hpp_options; /* flags controlling behaviour of the HP card */
+ u_short hpp_id; /* software revision and other fields */
+ caddr_t hpp_mem_start; /* Memory-mapped IO register address */
+
caddr_t mem_start; /* NIC memory start address */
caddr_t mem_end; /* NIC memory end address */
u_long mem_size; /* total NIC memory size */
@@ -146,6 +154,7 @@ static int ed_probe_WD80x3 __P((struct isa_device *));
static int ed_probe_3Com __P((struct isa_device *));
static int ed_probe_Novell __P((struct isa_device *));
static int ed_probe_Novell_generic __P((struct ed_softc *, int, int, int));
+static int ed_probe_HP_pclanp __P((struct isa_device *));
#include "pci.h"
#if NPCI > 0
@@ -165,6 +174,11 @@ static void ed_rint __P((struct ed_softc *));
static void ed_xmit __P((struct ed_softc *));
static char * ed_ring_copy __P((struct ed_softc *, char *, char *,
/* u_short */ int));
+static void ed_hpp_set_physical_link __P((struct ed_softc *));
+static void ed_hpp_readmem __P((struct ed_softc *, int, unsigned char *,
+ /* u_short */ int));
+static u_short ed_hpp_write_mbufs __P((struct ed_softc *, struct mbuf *,
+ int));
static void ed_pio_readmem __P((struct ed_softc *, int, unsigned char *,
/* u_short */ int));
@@ -172,8 +186,10 @@ static void ed_pio_writemem __P((struct ed_softc *, char *,
/* u_short */ int, /* u_short */ int));
static u_short ed_pio_write_mbufs __P((struct ed_softc *, struct mbuf *,
int));
+void edintr_sc __P((struct ed_softc *));
static void ed_setrcr(struct ed_softc *);
+
static u_long ds_crc(u_char *ep);
#if NCRD > 0
@@ -190,8 +206,6 @@ static void edunload(struct pccard_dev *); /* Disable driver */
static void edsuspend(struct pccard_dev *); /* Suspend driver */
static int edinit(struct pccard_dev *, int); /* init device */
-void edintr_sc __P((struct ed_softc *));
-
static struct pccard_drv ed_info = {
"ed",
card_intr,
@@ -325,6 +339,29 @@ static unsigned short ed_790_intr_mask[] = {
IRQ15
};
+/*
+ * Interrupt conversion table for the HP PC LAN+
+ */
+
+static unsigned short ed_hpp_intr_mask[] = {
+ 0, /* 0 */
+ 0, /* 1 */
+ 0, /* 2 */
+ IRQ3, /* 3 */
+ IRQ4, /* 4 */
+ IRQ5, /* 5 */
+ IRQ6, /* 6 */
+ IRQ7, /* 7 */
+ 0, /* 8 */
+ IRQ9, /* 9 */
+ IRQ10, /* 10 */
+ IRQ11, /* 11 */
+ IRQ12, /* 12 */
+ 0, /* 13 */
+ 0, /* 14 */
+ IRQ15 /* 15 */
+};
+
static struct kern_devconf kdc_ed_template = {
0, 0, 0, /* filled in by dev_attach */
"ed", 0, { MDDT_ISA, 0, "net" },
@@ -386,6 +423,10 @@ ed_probe(isa_dev)
if (nports)
return (nports);
+ nports = ed_probe_HP_pclanp(isa_dev);
+ if (nports)
+ return (nports);
+
return (0);
}
@@ -1432,6 +1473,325 @@ ed_probe_pccard(isa_dev, ether)
#endif /* NCRD > 0 */
+#define ED_HPP_TEST_SIZE 16
+
+/*
+ * Probe and vendor specific initialization for the HP PC Lan+ Cards.
+ * (HP Part nos: 27247B and 27252A).
+ *
+ * The card has an asic wrapper around a DS8390 core. The asic handles
+ * host accesses and offers both standard register IO and memory mapped
+ * IO. Memory mapped I/O allows better performance at the expense of greater
+ * chance of an incompatibility with existing ISA cards.
+ *
+ * The card has a few caveats: it isn't tolerant of byte wide accesses, only
+ * short (16 bit) or word (32 bit) accesses are allowed. Some card revisions
+ * don't allow 32 bit accesses; these are indicated by a bit in the software
+ * ID register (see if_edreg.h).
+ *
+ * Other caveats are: we should read the MAC address only when the card
+ * is inactive.
+ *
+ * For more information; please consult the CRYNWR packet driver.
+ *
+ * The AUI port is turned on using the "link2" option on the ifconfig
+ * command line.
+ */
+static int
+ed_probe_HP_pclanp(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int n; /* temp var */
+ int memsize; /* mem on board */
+ u_char checksum; /* checksum of board address */
+ u_char irq; /* board configured IRQ */
+ char test_pattern[ED_HPP_TEST_SIZE]; /* read/write areas for */
+ char test_buffer[ED_HPP_TEST_SIZE]; /* probing card */
+
+
+ /* Fill in basic information */
+ sc->asic_addr = isa_dev->id_iobase + ED_HPP_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_HPP_NIC_OFFSET;
+ sc->is790 = 0;
+ sc->isa16bit = 0; /* the 8390 core needs to be in byte mode */
+
+ /*
+ * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53"
+ */
+
+ if ((inb(sc->asic_addr + ED_HPP_ID) != 0x50) ||
+ (inb(sc->asic_addr + ED_HPP_ID + 1) != 0x48) ||
+ ((inb(sc->asic_addr + ED_HPP_ID + 2) & 0xF0) != 0) ||
+ (inb(sc->asic_addr + ED_HPP_ID + 3) != 0x53))
+ return 0;
+
+ /*
+ * Read the MAC address and verify checksum on the address.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_MAC);
+ for (n = 0, checksum = 0; n < ETHER_ADDR_LEN; n++)
+ checksum += (sc->arpcom.ac_enaddr[n] =
+ inb(sc->asic_addr + ED_HPP_MAC_ADDR + n));
+
+ checksum += inb(sc->asic_addr + ED_HPP_MAC_ADDR + ETHER_ADDR_LEN);
+
+ if (checksum != 0xFF)
+ return 0;
+
+ /*
+ * Verify that the software model number is 0.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_ID);
+ if (((sc->hpp_id = inw(sc->asic_addr + ED_HPP_PAGE_4)) &
+ ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000)
+ return 0;
+
+ /*
+ * Read in and save the current options configured on card.
+ */
+
+ sc->hpp_options = inw(sc->asic_addr + ED_HPP_OPTION);
+
+ sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET |
+ ED_HPP_OPTION_CHIP_RESET |
+ ED_HPP_OPTION_ENABLE_IRQ);
+
+ /*
+ * Reset the chip. This requires writing to the option register
+ * so take care to preserve the other bits.
+ */
+
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET |
+ ED_HPP_OPTION_CHIP_RESET)));
+
+ DELAY(5000); /* wait for chip reset to complete */
+
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET |
+ ED_HPP_OPTION_CHIP_RESET |
+ ED_HPP_OPTION_ENABLE_IRQ)));
+
+ DELAY(5000);
+
+ if (!(inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST))
+ return 0; /* reset did not complete */
+
+ /*
+ * Read out configuration information.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_HW);
+
+ irq = inb(sc->asic_addr + ED_HPP_HW_IRQ);
+
+ /*
+ * Check for impossible IRQ.
+ */
+
+ if (irq >= (sizeof(ed_hpp_intr_mask) / sizeof(ed_hpp_intr_mask[0])))
+ return 0;
+
+ /*
+ * If the kernel IRQ was specified with a '?' use the cards idea
+ * of the IRQ. If the kernel IRQ was explicitly specified, it
+ * should match that of the hardware.
+ */
+
+ if (isa_dev->id_irq <= 0)
+ isa_dev->id_irq = ed_hpp_intr_mask[irq];
+ else if (isa_dev->id_irq != ed_hpp_intr_mask[irq])
+ return 0;
+
+ /*
+ * Fill in softconfig info.
+ */
+
+ sc->vendor = ED_VENDOR_HP;
+ sc->type = ED_TYPE_HP_PCLANPLUS;
+ sc->type_str = "HP-PCLAN+";
+ sc->kdc.kdc_description = "Ethernet adapter: HP PCLAN+ (27247B/27252A)";
+
+ sc->mem_shared = 0; /* we DON'T have dual ported RAM */
+ sc->mem_start = 0; /* we use offsets inside the card RAM */
+
+ sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */
+
+ /*
+ * Check if memory mapping of the I/O registers possible.
+ */
+
+ if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE)
+ {
+ u_long mem_addr;
+
+ /*
+ * determine the memory address from the board.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_HW);
+ mem_addr = (inw(sc->asic_addr + ED_HPP_HW_MEM_MAP) << 8);
+
+ /*
+ * Check that the kernel specified start of memory and
+ * hardware's idea of it match.
+ */
+
+ if (mem_addr != kvtop(isa_dev->id_maddr))
+ return 0;
+
+ sc->hpp_mem_start = isa_dev->id_maddr;
+ }
+
+ /*
+ * The board has 32KB of memory. Is there a way to determine
+ * this programmatically?
+ */
+
+ memsize = 32768;
+
+ /*
+ * Fill in the rest of the soft config structure.
+ */
+
+ /*
+ * The transmit page index.
+ */
+
+ sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET;
+
+ if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ /*
+ * Memory description
+ */
+
+ sc->mem_size = memsize;
+ sc->mem_ring = sc->mem_start +
+ (sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ sc->mem_end = sc->mem_start + sc->mem_size;
+
+ /*
+ * Receive area starts after the transmit area and
+ * continues till the end of memory.
+ */
+
+ sc->rec_page_start = sc->tx_page_start +
+ (sc->txb_cnt * ED_TXBUF_SIZE);
+ sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE);
+
+
+ sc->cr_proto = 0; /* value works */
+
+ /*
+ * Set the wrap registers for string I/O reads.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_HW);
+ outw(sc->asic_addr + ED_HPP_HW_WRAP,
+ ((sc->rec_page_start / ED_PAGE_SIZE) |
+ (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8)));
+
+ /*
+ * Reset the register page to normal operation.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_PERF);
+
+ /*
+ * Verify that we can read/write from adapter memory.
+ * Create test pattern.
+ */
+
+ for (n = 0; n < ED_HPP_TEST_SIZE; n++)
+ {
+ test_pattern[n] = (n*n) ^ ~n;
+ }
+
+#undef ED_HPP_TEST_SIZE
+
+ /*
+ * Check that the memory is accessible thru the I/O ports.
+ * Write out the contents of "test_pattern", read back
+ * into "test_buffer" and compare the two for any
+ * mismatch.
+ */
+
+ for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) {
+
+ ed_pio_writemem(sc, test_pattern, (n * ED_PAGE_SIZE),
+ sizeof(test_pattern));
+ ed_pio_readmem(sc, (n * ED_PAGE_SIZE),
+ test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer,
+ sizeof(test_pattern)))
+ return 0;
+ }
+
+ return (ED_HPP_IO_PORTS);
+
+}
+
+/*
+ * HP PC Lan+ : Set the physical link to use AUI or TP/TL.
+ */
+
+void
+ed_hpp_set_physical_link(struct ed_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int lan_page;
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_LAN);
+ lan_page = inw(sc->asic_addr + ED_HPP_PAGE_0);
+
+ if (ifp->if_flags & IFF_ALTPHYS) {
+
+ /*
+ * Use the AUI port.
+ */
+
+ lan_page |= ED_HPP_LAN_AUI;
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_LAN);
+ outw(sc->asic_addr + ED_HPP_PAGE_0, lan_page);
+
+
+ } else {
+
+ /*
+ * Use the ThinLan interface
+ */
+
+ lan_page &= ~ED_HPP_LAN_AUI;
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_LAN);
+ outw(sc->asic_addr + ED_HPP_PAGE_0, lan_page);
+
+ }
+
+ /*
+ * Wait for the lan card to re-initialize itself
+ */
+
+ DELAY(150000); /* wait 150 ms */
+
+ /*
+ * Restore normal pages.
+ */
+
+ outw(sc->asic_addr + ED_HPP_PAGING, ED_HPP_PAGE_PERF);
+
+}
+
+
/*
* Install interface into kernel networking data structures
*/
@@ -1494,10 +1854,16 @@ ed_attach(sc, unit, flags)
else
printf("type unknown (0x%x) ", sc->type);
- printf("%s ", sc->isa16bit ? "(16 bit)" : "(8 bit)");
+ if (sc->vendor == ED_VENDOR_HP)
+ printf("(%s %s IO)", (sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS) ?
+ "16-bit" : "32-bit",
+ sc->hpp_mem_start ? "memory mapped" : "regular");
+ else
+ printf("%s ", sc->isa16bit ? "(16 bit)" : "(8 bit)");
- printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
- (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
+ printf("%s\n", (((sc->vendor == ED_VENDOR_3COM) ||
+ (sc->vendor == ED_VENDOR_HP)) &&
+ (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
/*
* If BPF is in the kernel, call the attach for it
@@ -2378,7 +2744,8 @@ ed_ioctl(ifp, command, data)
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
- }
+ } else if (sc->vendor == ED_VENDOR_HP)
+ ed_hpp_set_physical_link(sc);
break;
case SIOCADDMULTI:
@@ -2556,6 +2923,13 @@ ed_pio_readmem(sc, src, dst, amount)
unsigned char *dst;
unsigned short amount;
{
+ /* HP cards need special handling */
+ if (sc->vendor == ED_VENDOR_HP && sc->type == ED_TYPE_HP_PCLANPLUS) {
+ ed_hpp_readmem(sc, src, dst, amount);
+ return;
+ }
+
+ /* Regular Novell cards */
/* select page 0 registers */
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
@@ -2594,36 +2968,84 @@ ed_pio_writemem(sc, src, dst, len)
{
int maxwait = 200; /* about 240us */
- /* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
+ if (sc->vendor == ED_VENDOR_NOVELL) {
- /* reset remote DMA complete flag */
- outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
- /* set up DMA byte count */
- outb(sc->nic_addr + ED_P0_RBCR0, len);
- outb(sc->nic_addr + ED_P0_RBCR1, len >> 8);
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
- /* set up destination address in NIC mem */
- outb(sc->nic_addr + ED_P0_RSAR0, dst);
- outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8);
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len >> 8);
- /* set remote DMA write */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8);
- if (sc->isa16bit)
- outsw(sc->asic_addr + ED_NOVELL_DATA, src, len / 2);
- else
- outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
- /*
- * Wait for remote DMA complete. This is necessary because on the
- * transmit side, data is handled internally by the NIC in bursts and
- * we can't start another remote DMA until this one completes. Not
- * waiting causes really bad things to happen - like the NIC
- * irrecoverably jamming the ISA bus.
- */
- while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+ if (sc->isa16bit)
+ outsw(sc->asic_addr + ED_NOVELL_DATA, src, len / 2);
+ else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts and
+ * we can't start another remote DMA until this one completes. Not
+ * waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+
+ } else if ((sc->vendor == ED_VENDOR_HP) &&
+ (sc->type == ED_TYPE_HP_PCLANPLUS)) {
+
+ /* HP PCLAN+ */
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* program the write address in RAM */
+ outw(sc->asic_addr + ED_HPP_PAGE_0, dst);
+
+ if (sc->hpp_mem_start) {
+ u_short *s = (u_short *) src;
+ volatile u_short *d = (u_short *) sc->hpp_mem_start;
+ u_short *const fence = s + (len >> 1);
+
+ /*
+ * Enable memory mapped access.
+ */
+
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ sc->hpp_options &
+ ~(ED_HPP_OPTION_MEM_DISABLE |
+ ED_HPP_OPTION_BOOT_ROM_ENB));
+
+ /*
+ * Copy to NIC memory.
+ */
+
+ while (s < fence)
+ *d = *s++;
+
+ /*
+ * Restore Boot ROM access.
+ */
+
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ sc->hpp_options);
+
+ } else {
+ /* write data using I/O writes */
+ outsw(sc->asic_addr + ED_HPP_PAGE_4, src, len / 2);
+ }
+
+ }
}
/*
@@ -2641,6 +3063,12 @@ ed_pio_write_mbufs(sc, m, dst)
struct mbuf *mp;
int maxwait = 200; /* about 240us */
+ /* HP PC Lan+ cards need special handling */
+ if ((sc->vendor == ED_VENDOR_HP) &&
+ (sc->type == ED_TYPE_HP_PCLANPLUS)) {
+ return ed_hpp_write_mbufs(sc, m, dst);
+ }
+
/* First, count up the total number of bytes to copy */
for (total_len = 0, mp = m; mp; mp = mp->m_next)
total_len += mp->m_len;
@@ -2740,6 +3168,240 @@ ed_pio_write_mbufs(sc, m, dst)
return (total_len);
}
+/*
+ * Support routines to handle the HP PC Lan+ card.
+ */
+
+/*
+ * HP PC Lan+: Read from NIC memory, using either PIO or memory mapped
+ * IO.
+ */
+
+static void
+ed_hpp_readmem(sc, src, dst, amount)
+ struct ed_softc *sc;
+ unsigned short src;
+ unsigned char *dst;
+ unsigned short amount;
+{
+
+ int use_32bit_access = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS);
+
+
+ /* Program the source address in RAM */
+ outw(sc->asic_addr + ED_HPP_PAGE_2, src);
+
+ /*
+ * The HP PC Lan+ card supports word reads as well as
+ * a memory mapped i/o port that is aliased to every
+ * even address on the board.
+ */
+
+ if (sc->hpp_mem_start) {
+
+ /* Enable memory mapped access. */
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ sc->hpp_options &
+ ~(ED_HPP_OPTION_MEM_DISABLE |
+ ED_HPP_OPTION_BOOT_ROM_ENB));
+
+ if (use_32bit_access && (amount > 3)) {
+ u_long *dl = (u_long *) dst;
+ volatile u_long *const sl =
+ (u_long *) sc->hpp_mem_start;
+ u_long *const fence = dl + (amount >> 2);
+
+ /* Copy out NIC data. We could probably write this
+ as a `movsl'. The currently generated code is lousy.
+ */
+
+ while (dl < fence)
+ *dl++ = *sl;
+
+ dst += (amount & ~3);
+ amount &= 3;
+
+ }
+
+ /* Finish off any words left, as a series of short reads */
+ if (amount > 1) {
+ u_short *d = (u_short *) dst;
+ volatile u_short *const s =
+ (u_short *) sc->hpp_mem_start;
+ u_short *const fence = d + (amount >> 1);
+
+ /* Copy out NIC data. */
+
+ while (d < fence)
+ *d++ = *s;
+
+ dst += (amount & ~1);
+ amount &= 1;
+ }
+
+ /*
+ * read in a byte; however we need to always read 16 bits
+ * at a time or the hardware gets into a funny state
+ */
+
+ if (amount == 1) {
+ /* need to read in a short and copy LSB */
+ volatile u_short *const s =
+ (volatile u_short *) sc->hpp_mem_start;
+
+ *dst = (*s) & 0xFF;
+ }
+
+ /* Restore Boot ROM access. */
+
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ sc->hpp_options);
+
+
+ } else {
+ /* Read in data using the I/O port */
+ if (use_32bit_access && (amount > 3)) {
+ insl(sc->asic_addr + ED_HPP_PAGE_4, dst, amount >> 2);
+ dst += (amount & ~3);
+ amount &= 3;
+ }
+ if (amount > 1) {
+ insw(sc->asic_addr + ED_HPP_PAGE_4, dst, amount >> 1);
+ dst += (amount & ~1);
+ amount &= 1;
+ }
+ if (amount == 1) { /* read in a short and keep the LSB */
+ *dst = inw(sc->asic_addr + ED_HPP_PAGE_4) & 0xFF;
+ }
+ }
+}
+
+/*
+ * Write to HP PC Lan+ NIC memory. Access to the NIC can be by using
+ * outsw() or via the memory mapped interface to the same register.
+ * Writes have to be in word units; byte accesses won't work and may cause
+ * the NIC to behave wierdly. Long word accesses are permitted if the ASIC
+ * allows it.
+ */
+
+static u_short
+ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, int dst)
+{
+ int len, wantbyte;
+ unsigned short total_len;
+ unsigned char savebyte[2];
+ volatile u_short * const d =
+ (volatile u_short *) sc->hpp_mem_start;
+ int use_32bit_accesses = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS);
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* program the write address in RAM */
+ outw(sc->asic_addr + ED_HPP_PAGE_0, dst);
+
+ if (sc->hpp_mem_start) /* enable memory mapped I/O */
+ outw(sc->asic_addr + ED_HPP_OPTION, sc->hpp_options &
+ ~(ED_HPP_OPTION_MEM_DISABLE |
+ ED_HPP_OPTION_BOOT_ROM_ENB));
+
+ wantbyte = 0;
+ total_len = 0;
+
+ if (sc->hpp_mem_start) { /* Memory mapped I/O port */
+ while (m) {
+ total_len += (len = m->m_len);
+ if (len) {
+ caddr_t data = mtod(m, caddr_t);
+ /* finish the last word of the previous mbuf */
+ if (wantbyte) {
+ savebyte[1] = *data;
+ *d = *((ushort *) savebyte);
+ data++; len--; wantbyte = 0;
+ }
+ /* output contiguous words */
+ if ((len > 3) && (use_32bit_accesses)) {
+ volatile u_long *const dl =
+ (volatile u_long *) d;
+ u_long *sl = (u_long *) data;
+ u_long *fence = sl + (len >> 2);
+
+ while (sl < fence)
+ *dl = *sl++;
+
+ data += (len & ~3);
+ len &= 3;
+ }
+ /* finish off remain 16 bit writes */
+ if (len > 1) {
+ u_short *s = (u_short *) data;
+ u_short *fence = s + (len >> 1);
+
+ while (s < fence)
+ *d = *s++;
+
+ data += (len & ~1);
+ len &= 1;
+ }
+ /* save last byte if needed */
+ if (wantbyte = (len == 1))
+ savebyte[0] = *data;
+ }
+ m = m->m_next; /* to next mbuf */
+ }
+ if (wantbyte) /* write last byte */
+ *d = *((u_short *) savebyte);
+ } else {
+ /* use programmed I/O */
+ while (m) {
+ total_len += (len = m->m_len);
+ if (len) {
+ caddr_t data = mtod(m, caddr_t);
+ /* finish the last word of the previous mbuf */
+ if (wantbyte) {
+ savebyte[1] = *data;
+ outw(sc->asic_addr + ED_HPP_PAGE_4,
+ *((u_short *)savebyte));
+ data++;
+ len--;
+ wantbyte = 0;
+ }
+ /* output contiguous words */
+ if ((len > 3) && use_32bit_accesses) {
+ outsl(sc->asic_addr + ED_HPP_PAGE_4,
+ data, len >> 2);
+ data += (len & ~3);
+ len &= 3;
+ }
+ /* finish off remaining 16 bit accesses */
+ if (len > 1) {
+ outsw(sc->asic_addr + ED_HPP_PAGE_4,
+ data, len >> 1);
+ data += (len & ~1);
+ len &= 1;
+ }
+ if (wantbyte = (len == 1))
+ savebyte[0] = *data;
+
+ } /* if len != 0 */
+ m = m->m_next;
+ }
+ if (wantbyte) /* spit last byte */
+ outw(sc->asic_addr + ED_HPP_PAGE_4,
+ *(u_short *)savebyte);
+
+ }
+
+ if (sc->hpp_mem_start) /* turn off memory mapped i/o */
+ outw(sc->asic_addr + ED_HPP_OPTION,
+ sc->hpp_options);
+
+ return (total_len);
+}
+
static void
ed_setrcr(sc)
struct ed_softc *sc;
diff --git a/sys/dev/ed/if_edreg.h b/sys/dev/ed/if_edreg.h
index a03ce65..db7db18 100644
--- a/sys/dev/ed/if_edreg.h
+++ b/sys/dev/ed/if_edreg.h
@@ -6,7 +6,7 @@
* of this software, nor does the author assume any responsibility
* for damages incurred with its use.
*
- * $Id: if_edreg.h,v 1.19 1995/09/26 08:57:45 phk Exp $
+ * $Id: if_edreg.h,v 1.20 1996/01/30 22:55:38 mpp Exp $
*/
/*
* National Semiconductor DS8390 NIC register definitions
@@ -569,6 +569,7 @@ struct ed_ring {
#define ED_VENDOR_3COM 0x01 /* 3Com */
#define ED_VENDOR_NOVELL 0x02 /* Novell */
#define ED_VENDOR_PCCARD 0x03 /* PCMCIA/PCCARD */
+#define ED_VENDOR_HP 0x04 /* Hewlett Packard */
/*
* Compile-time config flags
@@ -1001,3 +1002,86 @@ struct ed_ring {
#define ZE_MISC 0x18
#define ZE_RESET 0x1F
+/*
+ * Definitions for HP PC LAN Adapter Plus; based on the CRYNWR packet
+ * driver for the card.
+ */
+
+#define ED_HPP_ASIC_OFFSET 0x00 /* Offset to ASIC registers */
+#define ED_HPP_NIC_OFFSET 0x10 /* Offset to 8390 registers */
+
+#define ED_HPP_ID 0x00 /* ID register, always 0x4850 */
+#define ED_HPP_PAGING 0x02 /* Page select register */
+#define ED_HPP_OPTION 0x04 /* Bitmask of supported options */
+#define ED_HPP_PAGE_0 0x08 /* Page 0 */
+#define ED_HPP_PAGE_2 0x0A /* Page 2 */
+#define ED_HPP_PAGE_4 0x0C /* Page 4 */
+#define ED_HPP_PAGE_6 0x0E /* Page 6 */
+
+/* PERF PAGE */
+#define ED_HPP_OUT_ADDR ED_HPP_PAGE_0 /* I/O output location */
+#define ED_HPP_IN_ADDR ED_HPP_PAGE_2 /* I/O input location */
+#define ED_HPP_DATAPORT ED_HPP_PAGE_4 /* I/O data transfer */
+/* MAC PAGE */
+#define ED_HPP_MAC_ADDR 0x08 /* Offset of MAC address in MAC page */
+
+#define ED_HPP_IO_PORTS 32 /* Number of IO ports */
+
+#define ED_HPP_TX_PAGE_OFFSET 0x00 /* first page of TX buffer */
+#define ED_HPP_RX_PAGE_START 0x06 /* start at page 6 */
+#define ED_HPP_RX_PAGE_STOP 0x80 /* end at page 128 */
+
+/*
+ * Register pages supported.
+ */
+
+#define ED_HPP_PAGE_PERF 0 /* Normal operation */
+#define ED_HPP_PAGE_MAC 1 /* The ethernet address and checksum */
+#define ED_HPP_PAGE_HW 2 /* Hardware parameters in EEPROM */
+#define ED_HPP_PAGE_LAN 4 /* Transciever selection etc */
+#define ED_HPP_PAGE_ID 6 /* ID */
+
+/*
+ * Options supported.
+ */
+
+#define ED_HPP_OPTION_NIC_RESET 0x0001 /* active low */
+#define ED_HPP_OPTION_CHIP_RESET 0x0002 /* active low */
+#define ED_HPP_OPTION_ENABLE_IRQ 0x0004
+#define ED_HPP_OPTION_FAKE_INTR 0x0008
+#define ED_HPP_OPTION_BOOT_ROM_ENB 0x0010
+#define ED_HPP_OPTION_IO_ENB 0x0020
+#define ED_HPP_OPTION_MEM_ENABLE 0x0040
+#define ED_HPP_OPTION_ZERO_WAIT 0x0080
+#define ED_HPP_OPTION_MEM_DISABLE 0x1000
+
+/*
+ * Page ID configuration.
+ */
+
+#define ED_HPP_ID_REVISION_MASK 0x0300 /* revision id */
+#define ED_HPP_ID_SOFT_MODEL_MASK 0xFC00 /* soft model number */
+#define ED_HPP_ID_16_BIT_ACCESS 0x0010 /* if set use 16 bit accesses */
+#define ED_HPP_ID_TWISTED_PAIR 0x0040
+
+/*
+ * Hardware configuration.
+ */
+
+#define ED_HPP_HW_MEM_MAP 0x09 /* low mem map location in HW page */
+#define ED_HPP_HW_ID 0x0C /* revision number, capabilities */
+#define ED_HPP_HW_IRQ 0x0D /* IRQ channel register in HW page */
+#define ED_HPP_HW_WRAP 0x0E /* mem wrap page for rcv */
+
+/*
+ * Lan configuration
+ */
+
+#define ED_HPP_LAN_AUI 0x01 /* Use AUI */
+#define ED_HPP_LAN_TL 0x40 /* Don't use AUI */
+
+/*
+ * Card types.
+ */
+
+#define ED_TYPE_HP_PCLANPLUS 0x00
OpenPOWER on IntegriCloud