mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
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>
This commit is contained in:
parent
e3b68a1b89
commit
aea6ddfd4f
4 changed files with 1556 additions and 64 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue