linux/drivers/net/stnic.c

321 lines
7.5 KiB
C
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/* stnic.c : A SH7750 specific part of driver for NS DP83902A ST-NIC.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1999 kaz Kojima
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/se/se.h>
#include <asm/machvec.h>
#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
#endif
#include "8390.h"
#define DRV_NAME "stnic"
#define byte unsigned char
#define half unsigned short
#define word unsigned int
#define vbyte volatile unsigned char
#define vhalf volatile unsigned short
#define vword volatile unsigned int
#define STNIC_RUN 0x01 /* 1 == Run, 0 == reset. */
#define START_PG 0 /* First page of TX buffer */
#define STOP_PG 128 /* Last page +1 of RX ring */
/* Alias */
#define STNIC_CR E8390_CMD
#define PG0_RSAR0 EN0_RSARLO
#define PG0_RSAR1 EN0_RSARHI
#define PG0_RBCR0 EN0_RCNTLO
#define PG0_RBCR1 EN0_RCNTHI
#define CR_RRD E8390_RREAD
#define CR_RWR E8390_RWRITE
#define CR_PG0 E8390_PAGE0
#define CR_STA E8390_START
#define CR_RDMA E8390_NODMA
/* FIXME! YOU MUST SET YOUR OWN ETHER ADDRESS. */
static byte stnic_eadr[6] =
{0x00, 0xc0, 0x6e, 0x00, 0x00, 0x07};
static struct net_device *stnic_dev;
static int stnic_open (struct net_device *dev);
static int stnic_close (struct net_device *dev);
static void stnic_reset (struct net_device *dev);
static void stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void stnic_block_input (struct net_device *dev, int count,
struct sk_buff *skb , int ring_offset);
static void stnic_block_output (struct net_device *dev, int count,
const unsigned char *buf, int start_page);
static void stnic_init (struct net_device *dev);
/* SH7750 specific read/write io. */
static inline void
STNIC_DELAY (void)
{
vword trash;
trash = *(vword *) 0xa0000000;
trash = *(vword *) 0xa0000000;
trash = *(vword *) 0xa0000000;
}
static inline byte
STNIC_READ (int reg)
{
byte val;
val = (*(vhalf *) (PA_83902 + ((reg) << 1)) >> 8) & 0xff;
STNIC_DELAY ();
return val;
}
static inline void
STNIC_WRITE (int reg, byte val)
{
*(vhalf *) (PA_83902 + ((reg) << 1)) = ((half) (val) << 8);
STNIC_DELAY ();
}
static int __init stnic_probe(void)
{
struct net_device *dev;
int i, err;
/* If we are not running on a SolutionEngine, give up now */
if (! MACH_SE)
return -ENODEV;
/* New style probing API */
dev = alloc_ei_netdev();
if (!dev)
return -ENOMEM;
SET_MODULE_OWNER(dev);
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_get_node_addr (stnic_eadr);
#endif
for (i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = stnic_eadr[i];
/* Set the base address to point to the NIC, not the "real" base! */
dev->base_addr = 0x1000;
dev->irq = IRQ_STNIC;
dev->open = &stnic_open;
dev->stop = &stnic_close;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = ei_poll;
#endif
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
err = request_irq (dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (err) {
printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq);
free_netdev(dev);
return err;
}
ei_status.name = dev->name;
ei_status.word16 = 1;
#ifdef __LITTLE_ENDIAN__
ei_status.bigendian = 0;
#else
ei_status.bigendian = 1;
#endif
ei_status.tx_start_page = START_PG;
ei_status.rx_start_page = START_PG + TX_PAGES;
ei_status.stop_page = STOP_PG;
ei_status.reset_8390 = &stnic_reset;
ei_status.get_8390_hdr = &stnic_get_hdr;
ei_status.block_input = &stnic_block_input;
ei_status.block_output = &stnic_block_output;
stnic_init (dev);
err = register_netdev(dev);
if (err) {
free_irq(dev->irq, dev);
free_netdev(dev);
return err;
}
stnic_dev = dev;
printk (KERN_INFO "NS ST-NIC 83902A\n");
return 0;
}
static int
stnic_open (struct net_device *dev)
{
#if 0
printk (KERN_DEBUG "stnic open\n");
#endif
ei_open (dev);
return 0;
}
static int
stnic_close (struct net_device *dev)
{
ei_close (dev);
return 0;
}
static void
stnic_reset (struct net_device *dev)
{
*(vhalf *) PA_83902_RST = 0;
udelay (5);
if (ei_debug > 1)
printk (KERN_WARNING "8390 reset done (%ld).\n", jiffies);
*(vhalf *) PA_83902_RST = ~0;
udelay (5);
}
static void
stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page)
{
half buf[2];
STNIC_WRITE (PG0_RSAR0, 0);
STNIC_WRITE (PG0_RSAR1, ring_page);
STNIC_WRITE (PG0_RBCR0, 4);
STNIC_WRITE (PG0_RBCR1, 0);
STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA);
buf[0] = *(vhalf *) PA_83902_IF;
STNIC_DELAY ();
buf[1] = *(vhalf *) PA_83902_IF;
STNIC_DELAY ();
hdr->next = buf[0] >> 8;
hdr->status = buf[0] & 0xff;
#ifdef __LITTLE_ENDIAN__
hdr->count = buf[1];
#else
hdr->count = ((buf[1] >> 8) & 0xff) | (buf[1] << 8);
#endif
if (ei_debug > 1)
printk (KERN_DEBUG "ring %x status %02x next %02x count %04x.\n",
ring_page, hdr->status, hdr->next, hdr->count);
STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA);
}
/* Block input and output, similar to the Crynwr packet driver. If you are
porting to a new ethercard look at the packet driver source for hints.
The HP LAN doesn't use shared memory -- we put the packet
out through the "remote DMA" dataport. */
static void
stnic_block_input (struct net_device *dev, int length, struct sk_buff *skb,
int offset)
{
char *buf = skb->data;
half val;
STNIC_WRITE (PG0_RSAR0, offset & 0xff);
STNIC_WRITE (PG0_RSAR1, offset >> 8);
STNIC_WRITE (PG0_RBCR0, length & 0xff);
STNIC_WRITE (PG0_RBCR1, length >> 8);
STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA);
if (length & 1)
length++;
while (length > 0)
{
val = *(vhalf *) PA_83902_IF;
#ifdef __LITTLE_ENDIAN__
*buf++ = val & 0xff;
*buf++ = val >> 8;
#else
*buf++ = val >> 8;
*buf++ = val & 0xff;
#endif
STNIC_DELAY ();
length -= sizeof (half);
}
STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA);
}
static void
stnic_block_output (struct net_device *dev, int length,
const unsigned char *buf, int output_page)
{
STNIC_WRITE (PG0_RBCR0, 1); /* Write non-zero value */
STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA);
STNIC_DELAY ();
STNIC_WRITE (PG0_RBCR0, length & 0xff);
STNIC_WRITE (PG0_RBCR1, length >> 8);
STNIC_WRITE (PG0_RSAR0, 0);
STNIC_WRITE (PG0_RSAR1, output_page);
STNIC_WRITE (STNIC_CR, CR_RWR | CR_PG0 | CR_STA);
if (length & 1)
length++;
while (length > 0)
{
#ifdef __LITTLE_ENDIAN__
*(vhalf *) PA_83902_IF = ((half) buf[1] << 8) | buf[0];
#else
*(vhalf *) PA_83902_IF = ((half) buf[0] << 8) | buf[1];
#endif
STNIC_DELAY ();
buf += sizeof (half);
length -= sizeof (half);
}
STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA);
}
/* This function resets the STNIC if something screws up. */
static void
stnic_init (struct net_device *dev)
{
stnic_reset (dev);
NS8390_init (dev, 0);
return;
}
static void __exit stnic_cleanup(void)
{
unregister_netdev(stnic_dev);
free_irq(stnic_dev->irq, stnic_dev);
free_netdev(stnic_dev);
}
module_init(stnic_probe);
module_exit(stnic_cleanup);
MODULE_LICENSE("GPL");