Commit e61880e1 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Linus Torvalds

[PATCH] m68k: HP300 LANCE

HP300 LANCE updates from Kars de Jong:
  - Updated HP LANCE driver to use the new DIO semantics
  - If only HP LANCE or MVME147 LANCE is selected, enable compile-time
    choice of LANCE register access. If both are defined, go through the
    function pointer
  - Added support for CONFIG_NET_POLL_CONTROLLER
  - Fixed problem with disabling board interrupts in hplance_close() which
    caused the driver to lock up
Signed-off-by: default avatarKars de Jong <jongk@linux-m68k.org>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5c929ee3
This diff is collapsed.
......@@ -14,11 +14,8 @@
#define _7990_H
/* The lance only has two register locations. We communicate mostly via memory. */
struct lance_regs
{
unsigned short rdp; /* Register Data Port */
unsigned short rap; /* Register Address Port */
};
#define LANCE_RDP 0 /* Register Data Port */
#define LANCE_RAP 2 /* Register Address Port */
/* Transmit/receive ring definitions.
* We allow the specific drivers to override these defaults if they want to.
......@@ -104,7 +101,7 @@ struct lance_init_block {
struct lance_private
{
char *name;
volatile struct lance_regs *ll;
unsigned long base;
volatile struct lance_init_block *init_block; /* CPU address of RAM */
volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
......@@ -252,5 +249,8 @@ extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev);
extern struct net_device_stats *lance_get_stats (struct net_device *dev);
extern void lance_set_multicast (struct net_device *dev);
extern void lance_tx_timeout(struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
extern void lance_poll(struct net_device *dev);
#endif
#endif /* ndef _7990_H */
......@@ -42,7 +42,6 @@
struct hplance_private {
struct lance_private lance;
unsigned int scode;
void *base;
};
/* function prototypes... This is easy because all the grot is in the
......@@ -91,15 +90,17 @@ struct net_device * __init hplance_probe(int unit)
{
int scode = dio_find(DIO_ID_LAN);
if (!scode)
if (scode < 0)
break;
dio_config_board(scode);
hplance_init(dev, scode);
if (!register_netdev(dev)) {
#ifdef MODULE
struct hplance_private *lp = netdev_priv(dev);
lp->next_module = root_hplance_dev;
root_hplance_dev = lp;
#endif
return dev;
}
cleanup_card(dev);
......@@ -112,20 +113,24 @@ struct net_device * __init hplance_probe(int unit)
static void __init hplance_init(struct net_device *dev, int scode)
{
const char *name = dio_scodetoname(scode);
void *va = dio_scodetoviraddr(scode);
unsigned long pa = dio_scodetophysaddr(scode);
unsigned long va = (pa + DIO_VIRADDRBASE);
struct hplance_private *lp;
int i;
printk("%s: %s; select code %d, addr", dev->name, name, scode);
printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, name, scode);
/* reset the board */
out_8(va+DIO_IDOFF, 0xff);
udelay(100); /* ariba! ariba! udelay! udelay! */
/* Fill the dev fields */
dev->base_addr = (unsigned long)va;
dev->base_addr = va;
dev->open = &hplance_open;
dev->stop = &hplance_close;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = lance_poll;
#endif
dev->hard_start_xmit = &lance_start_xmit;
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
......@@ -143,7 +148,7 @@ static void __init hplance_init(struct net_device *dev, int scode)
lp = netdev_priv(dev);
lp->lance.name = (char*)name; /* discards const, shut up gcc */
lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
lp->lance.base = va;
lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
lp->lance.lance_init_block = 0; /* LANCE addr of same RAM */
lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
......@@ -156,7 +161,6 @@ static void __init hplance_init(struct net_device *dev, int scode)
lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
lp->scode = scode;
lp->base = va;
printk(", irq %d\n", lp->lance.irq);
}
......@@ -165,53 +169,49 @@ static void __init hplance_init(struct net_device *dev, int scode)
*/
static void hplance_writerap(void *priv, unsigned short value)
{
struct hplance_private *lp = (struct hplance_private *)priv;
struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
do {
lp->lance.ll->rap = value;
} while ((hpregs->status & LE_ACK) == 0);
struct lance_private *lp = (struct lance_private *)priv;
do {
out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
}
static void hplance_writerdp(void *priv, unsigned short value)
{
struct hplance_private *lp = (struct hplance_private *)priv;
struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
do {
lp->lance.ll->rdp = value;
} while ((hpregs->status & LE_ACK) == 0);
struct lance_private *lp = (struct lance_private *)priv;
do {
out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
}
static unsigned short hplance_readrdp(void *priv)
{
unsigned short val;
struct hplance_private *lp = (struct hplance_private *)priv;
struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
do {
val = lp->lance.ll->rdp;
} while ((hpregs->status & LE_ACK) == 0);
return val;
struct lance_private *lp = (struct lance_private *)priv;
__u16 value;
do {
value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
return value;
}
static int hplance_open(struct net_device *dev)
{
int status;
struct hplance_private *lp = netdev_priv(dev);
struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
struct lance_private *lp = netdev_priv(dev);
status = lance_open(dev); /* call generic lance open code */
if (status)
return status;
/* enable interrupts at board level. */
out_8(&(hpregs->status), LE_IE);
out_8(lp->base + HPLANCE_STATUS, LE_IE);
return 0;
}
static int hplance_close(struct net_device *dev)
{
struct hplance_private *lp = netdev_priv(dev);
struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
out_8(&(hpregs->status), 8); /* disable interrupts at boardlevel */
struct lance_private *lp = netdev_priv(dev);
out_8(lp->base + HPLANCE_STATUS, 0); /* disable interrupts at boardlevel */
lance_close(dev);
return 0;
}
......
......@@ -4,15 +4,10 @@
*/
/* Registers */
struct hplance_reg
{
u_char pad0;
volatile u_char id; /* DIO register: ID byte */
u_char pad1;
volatile u_char status; /* DIO register: interrupt enable */
};
#define HPLANCE_ID 0x01 /* DIO register: ID byte */
#define HPLANCE_STATUS 0x03 /* DIO register: interrupt enable/status */
/* Control and status bits for the hplance->status register */
/* Control and status bits for the status register */
#define LE_IE 0x80 /* interrupt enable */
#define LE_IR 0x40 /* interrupt requested */
#define LE_LOCK 0x08 /* lock status register */
......@@ -25,7 +20,7 @@ struct hplance_reg
/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
* memory and NVRAM:
*/
#define HPLANCE_IDOFF 0 /* board baseaddr, struct hplance_reg */
#define HPLANCE_REGOFF 0x4000 /* struct lance_regs */
#define HPLANCE_IDOFF 0 /* board baseaddr */
#define HPLANCE_REGOFF 0x4000 /* lance registers */
#define HPLANCE_MEMOFF 0x8000 /* struct lance_init_block */
#define HPLANCE_NVRAMOFF 0xC008 /* etheraddress as one *nibble* per byte */
......@@ -18,7 +18,6 @@
/* Used for the temporal inet entries and routing */
#include <linux/socket.h>
#include <linux/route.h>
#include <linux/dio.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
......@@ -40,7 +39,6 @@
/* Our private data structure */
struct m147lance_private {
struct lance_private lance;
void *base;
unsigned long ram;
};
......@@ -51,9 +49,9 @@ struct m147lance_private {
*/
static int m147lance_open(struct net_device *dev);
static int m147lance_close(struct net_device *dev);
static void m147lance_writerap(struct m147lance_private *lp, unsigned short value);
static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value);
static unsigned short m147lance_readrdp(struct m147lance_private *lp);
static void m147lance_writerap(struct lance_private *lp, unsigned short value);
static void m147lance_writerdp(struct lance_private *lp, unsigned short value);
static unsigned short m147lance_readrdp(struct lance_private *lp);
typedef void (*writerap_t)(void *, unsigned short);
typedef void (*writerdp_t)(void *, unsigned short);
......@@ -122,7 +120,7 @@ struct net_device * __init mvme147lance_probe(int unit)
}
lp->lance.name = (char*)name; /* discards const, shut up gcc */
lp->lance.ll = (struct lance_regs *)(dev->base_addr);
lp->lance.base = dev->base_addr;
lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */
lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram); /* LANCE addr of same RAM */
lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
......@@ -145,19 +143,19 @@ struct net_device * __init mvme147lance_probe(int unit)
return dev;
}
static void m147lance_writerap(struct m147lance_private *lp, unsigned short value)
static void m147lance_writerap(struct lance_private *lp, unsigned short value)
{
lp->lance.ll->rap = value;
out_be16(lp->base + LANCE_RAP, value);
}
static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value)
static void m147lance_writerdp(struct lance_private *lp, unsigned short value)
{
lp->lance.ll->rdp = value;
out_be16(lp->base + LANCE_RDP, value);
}
static unsigned short m147lance_readrdp(struct m147lance_private *lp)
static unsigned short m147lance_readrdp(struct lance_private *lp)
{
return lp->lance.ll->rdp;
return in_be16(lp->base + LANCE_RDP);
}
static int m147lance_open(struct net_device *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment