summaryrefslogtreecommitdiffstats
path: root/drivers/net/wan/z85230.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /drivers/net/wan/z85230.c
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'drivers/net/wan/z85230.c')
-rw-r--r--drivers/net/wan/z85230.c389
1 files changed, 342 insertions, 47 deletions
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index f6b385de5..2ff818b04 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -54,12 +54,23 @@
static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
-/*
+/**
+ * z8530_read_port:
+ * @p: port to read
+ *
* Provided port access methods. The Comtrol SV11 requires no delays
* between accesses and uses PC I/O. Some drivers may need a 5uS delay
+ *
+ * In the longer term this should become an architecture specific
+ * section so that this can become a generic driver interface for all
+ * platforms. For now we only handle PC I/O ports with or without the
+ * dread 5uS sanity delay.
+ *
+ * The caller must hold sufficient locks to avoid violating the horrible
+ * 5uS delay rule.
*/
-extern __inline__ int z8530_read_port(int p)
+extern __inline__ int z8530_read_port(unsigned long p)
{
u8 r=inb(Z8530_PORT_OF(p));
if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */
@@ -67,7 +78,23 @@ extern __inline__ int z8530_read_port(int p)
return r;
}
-extern __inline__ void z8530_write_port(int p, u8 d)
+/**
+ * z8530_write_port:
+ * @p: port to write
+ * @d: value to write
+ *
+ * Write a value to a port with delays if need be. Note that the
+ * caller must hold locks to avoid read/writes from other contexts
+ * violating the 5uS rule
+ *
+ * In the longer term this should become an architecture specific
+ * section so that this can become a generic driver interface for all
+ * platforms. For now we only handle PC I/O ports with or without the
+ * dread 5uS sanity delay.
+ */
+
+
+extern __inline__ void z8530_write_port(unsigned long p, u8 d)
{
outb(d,Z8530_PORT_OF(p));
if(p&Z8530_PORT_SLEEP)
@@ -80,8 +107,16 @@ static void z8530_rx_done(struct z8530_channel *c);
static void z8530_tx_done(struct z8530_channel *c);
-/*
- * Port accesses
+/**
+ * read_zsreg:
+ * @c: Z8530 channel to read from (2 per chip)
+ * @reg: Register to read
+ * FIXME: Use a spinlock.
+ *
+ * Most of the Z8530 registers are indexed off the control registers.
+ * A read is done by writing to the control register and reading the
+ * register back. We do the locking needed to protect this
+ * operation.
*/
extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
@@ -97,6 +132,14 @@ extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
return r;
}
+/**
+ * read_zsdata:
+ * @c: The Z8530 channel to read the data port from
+ *
+ * The data port provides fast access to some things. We still
+ * have all the 5uS delays to worry about.
+ */
+
extern inline u8 read_zsdata(struct z8530_channel *c)
{
u8 r;
@@ -104,6 +147,17 @@ extern inline u8 read_zsdata(struct z8530_channel *c)
return r;
}
+/**
+ * write_zsreg:
+ * @c: The Z8530 channel
+ * @reg: Register number
+ * @val: Value to write
+ *
+ * Write a value to an indexed register. Perform the locking needed
+ * to honour the irritating delay rules. We know about register 0
+ * being fast to access.
+ */
+
extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
{
unsigned long flags;
@@ -194,8 +248,16 @@ u8 z8530_hdlc_kilostream_85230[]=
EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
-/*
- * Flush the FIFO
+/**
+ * z8530_flush_fifo:
+ * @c: Channel to flush
+ *
+ * Flush the receive FIFO. There is no specific option for this, we
+ * blindly read bytes and discard them. Reading when there is no data
+ * is harmless. The 8530 has a 4 byte FIFO, the 85230 has 8 bytes.
+ *
+ * All locking is handled for the caller. On return data may still be
+ * present if it arrived during the flush.
*/
static void z8530_flush_fifo(struct z8530_channel *c)
@@ -213,7 +275,16 @@ static void z8530_flush_fifo(struct z8530_channel *c)
}
}
-/* Sets or clears DTR/RTS on the requested line */
+/**
+ * z8530_rtsdtr:
+ * @c: The Z8530 channel to contro;
+ * @set: 1 to set, 0 to clear
+ *
+ * Sets or clears DTR/RTS on the requested line. All locking is handled
+ * for the caller. For now we assume all boards use the actual RTS/DTR
+ * on the chip. Apparently one or two don't. We'll scream about them
+ * later.
+ */
static void z8530_rtsdtr(struct z8530_channel *c, int set)
{
@@ -224,9 +295,12 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
write_zsreg(c, R5, c->regs[5]);
}
-/*
- * Receive handler. This is much like the async one but not quite the
- * same or as complex
+/**
+ * z8530_rx:
+ * @c: Z8530 channel to process
+ *
+ * Receive handler for receiving in PIO mode. This is much like the
+ * async one but not quite the same or as complex
*
* Note: Its intended that this handler can easily be separated from
* the main code to run realtime. That'll be needed for some machines
@@ -238,9 +312,9 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
* other code - this is true in the RT case too.
*
* We only cover the sync cases for this. If you want 2Mbit async
- * do it yourself but consider medical assistance first.
- *
- * This non DMA synchronous mode is portable code.
+ * do it yourself but consider medical assistance first. This non DMA
+ * synchronous mode is portable code. The DMA mode assumes PCI like
+ * ISA DMA
*/
static void z8530_rx(struct z8530_channel *c)
@@ -303,8 +377,14 @@ static void z8530_rx(struct z8530_channel *c)
}
-/*
- * Z8530 transmit interrupt handler
+/**
+ * z8530_tx:
+ * @c: Z8530 channel to process
+ *
+ * Z8530 transmit interrupt handler for the PIO mode. The basic
+ * idea is to attempt to keep the FIFO fed. We fill as many bytes
+ * in as possible, its quite possible that we won't keep up with the
+ * data rate otherwise.
*/
static void z8530_tx(struct z8530_channel *c)
@@ -340,6 +420,17 @@ static void z8530_tx(struct z8530_channel *c)
write_zsctrl(c, RES_H_IUS);
}
+/**
+ * z8530_status:
+ * @chan: Z8530 channel to process
+ *
+ * A status event occured in PIO synchronous mode. There are several
+ * reasons the chip will bother us here. A transmit underrun means we
+ * failed to feed the chip fast enough and just broke a packet. A DCD
+ * change is a line up or down. We communicate that back to the protocol
+ * layer for synchronous PPP to renegotiate.
+ */
+
static void z8530_status(struct z8530_channel *chan)
{
u8 status=read_zsreg(chan, R0);
@@ -387,9 +478,14 @@ struct z8530_irqhandler z8530_sync=
EXPORT_SYMBOL(z8530_sync);
-/*
+/**
+ * z8530_dma_rx:
+ * @chan: Channel to handle
+ *
* Non bus mastering DMA interfaces for the Z8x30 devices. This
- * is really pretty PC specific.
+ * is really pretty PC specific. The DMA mode means that most receive
+ * events are handled by the DMA hardware. We get a kick here only if
+ * a frame ended.
*/
static void z8530_dma_rx(struct z8530_channel *chan)
@@ -417,6 +513,14 @@ static void z8530_dma_rx(struct z8530_channel *chan)
}
}
+/**
+ * z8530_dma_tx:
+ * @chan: The Z8530 channel to handle
+ *
+ * We have received an interrupt while doing DMA transmissions. It
+ * shouldn't happen. Scream loudly if it does.
+ */
+
static void z8530_dma_tx(struct z8530_channel *chan)
{
if(!chan->dma_tx)
@@ -430,6 +534,17 @@ static void z8530_dma_tx(struct z8530_channel *chan)
z8530_tx(chan);
}
+/**
+ * z8530_dma_status:
+ * @chan: Z8530 channel to process
+ *
+ * A status event occured on the Z8530. We receive these for two reasons
+ * when in DMA mode. Firstly if we finished a packet transfer we get one
+ * and kick the next packet out. Secondly we may see a DCD change and
+ * have to poke the protocol layer.
+ *
+ */
+
static void z8530_dma_status(struct z8530_channel *chan)
{
unsigned long flags;
@@ -490,8 +605,11 @@ struct z8530_irqhandler z8530_txdma_sync=
EXPORT_SYMBOL(z8530_txdma_sync);
-/*
- * Interrupt vectors for a Z8530 that is in 'parked' mode.
+/**
+ * z8530_rx_clear:
+ * @c: Z8530 channel to shut up
+ *
+ * Receive interrupt vectors for a Z8530 that is in 'parked' mode.
* For machines with PCI Z85x30 cards, or level triggered interrupts
* (eg the MacII) we must clear the interrupt cause or die.
*/
@@ -516,12 +634,30 @@ static void z8530_rx_clear(struct z8530_channel *c)
write_zsctrl(c, RES_H_IUS);
}
+/**
+ * z8530_tx_clear:
+ * @c: Z8530 channel to shut up
+ *
+ * Transmit interrupt vectors for a Z8530 that is in 'parked' mode.
+ * For machines with PCI Z85x30 cards, or level triggered interrupts
+ * (eg the MacII) we must clear the interrupt cause or die.
+ */
+
static void z8530_tx_clear(struct z8530_channel *c)
{
write_zsctrl(c, RES_Tx_P);
write_zsctrl(c, RES_H_IUS);
}
+/**
+ * z8530_status_clear:
+ * @chan: Z8530 channel to shut up
+ *
+ * Status interrupt vectors for a Z8530 that is in 'parked' mode.
+ * For machines with PCI Z85x30 cards, or level triggered interrupts
+ * (eg the MacII) we must clear the interrupt cause or die.
+ */
+
static void z8530_status_clear(struct z8530_channel *chan)
{
u8 status=read_zsreg(chan, R0);
@@ -541,8 +677,17 @@ struct z8530_irqhandler z8530_nop=
EXPORT_SYMBOL(z8530_nop);
-/*
- * A Z85[2]30 device has stuck its hand in the air for attention
+/**
+ * z8530_interrupt:
+ * @irq: Interrupt number
+ * @dev_id: The Z8530 device that is interrupting.
+ * @regs: unused
+ *
+ * A Z85[2]30 device has stuck its hand in the air for attention.
+ * We scan both the channels on the chip for events and then call
+ * the channel specific call backs for each channel that has events.
+ * We have to use callback functions because the two channels can be
+ * in different modes.
*/
void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -612,6 +757,15 @@ static char reg_init[16]=
};
+/**
+ * z8530_sync_open:
+ * @dev: The network interface we are using
+ * @c: The Z8530 channel to open in synchronous PIO mode
+ *
+ * Switch a Z8530 into synchronous mode without DMA assist. We
+ * raise the RTS/DTR and commence network operation.
+ */
+
int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
{
c->sync = 1;
@@ -634,9 +788,19 @@ int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_open);
+/**
+ * z8530_sync_close:
+ * @dev: Network device to close
+ * @c: Z8530 channel to disassociate and move to idle
+ *
+ * Close down a Z8530 interface and switch its interrupt handlers
+ * to discard future events.
+ */
+
int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
{
u8 chk;
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
@@ -649,6 +813,16 @@ int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_close);
+/**
+ * z8530_sync_dma_open:
+ * @dev: The network device to attach
+ * @c: The Z8530 channel to configure in sync DMA mode.
+ *
+ * Set up a Z85x30 device for synchronous DMA in both directions. Two
+ * ISA DMA channels must be available for this to work. We assume ISA
+ * DMA driven I/O and PC limits on access.
+ */
+
int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
@@ -753,11 +927,21 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
c->irqs = &z8530_dma_sync;
z8530_rtsdtr(c,1);
write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+
return 0;
}
EXPORT_SYMBOL(z8530_sync_dma_open);
+/**
+ * z8530_sync_dma_close:
+ * @dev: Network device to detach
+ * @c: Z8530 channel to move into discard mode
+ *
+ * Shut down a DMA mode synchronous interface. Halt the DMA, and
+ * free the buffers.
+ */
+
int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
{
u8 chk;
@@ -814,6 +998,16 @@ int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_dma_close);
+/**
+ * z8530_sync_txdma_open:
+ * @dev: The network device to attach
+ * @c: The Z8530 channel to configure in sync DMA mode.
+ *
+ * Set up a Z85x30 device for synchronous DMA tranmission. One
+ * ISA DMA channel must be available for this to work. The receive
+ * side is run in PIO mode, but then it has the bigger FIFO.
+ */
+
int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
@@ -898,15 +1092,26 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
z8530_rtsdtr(c,1);
printk("Rx interrupts ON\n");
write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+
return 0;
}
EXPORT_SYMBOL(z8530_sync_txdma_open);
-
+
+/**
+ * z8530_sync_txdma_close:
+ * @dev: Network device to detach
+ * @c: Z8530 channel to move into discard mode
+ *
+ * Shut down a DMA/PIO split mode synchronous interface. Halt the DMA,
+ * and free the buffers.
+ */
+
int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
u8 chk;
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
@@ -950,21 +1155,32 @@ int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_txdma_close);
+
/*
- * Describe a Z8530 in a standard format. We must pass the I/O as
- * the port offset isnt predictable. The main reason for this function
- * is to try and get a common format of report.
+ * Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny
+ * it exists...
*/
-
+
static char *z8530_type_name[]={
"Z8530",
"Z85C30",
"Z85230"
};
-void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
+/**
+ * z8530_describe:
+ * @dev: Z8530 device to describe
+ * @mapping: string holding mapping type (eg "I/O" or "Mem")
+ * @io: the port value in question
+ *
+ * Describe a Z8530 in a standard format. We must pass the I/O as
+ * the port offset isnt predictable. The main reason for this function
+ * is to try and get a common format of report.
+ */
+
+void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io)
{
- printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",
+ printk(KERN_INFO "%s: %s found at %s 0x%lX, IRQ %d.\n",
dev->name,
z8530_type_name[dev->type],
mapping,
@@ -974,8 +1190,21 @@ void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
EXPORT_SYMBOL(z8530_describe);
-/*
- * Configure up a Z8530
+/**
+ * z8530_init:
+ * @dev: Z8530 device to initialise.
+ *
+ * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device
+ * is present, identify the type and then program it to hopefully
+ * keep quite and behave. This matters a lot, a Z8530 in the wrong
+ * state will sometimes get into stupid modes generating 10Khz
+ * interrupt streams and the like.
+ *
+ * We set the interrupt handler up to discard any events, in case
+ * we get them during reset or setp.
+ *
+ * Return 0 for success, or a negative value indicating the problem
+ * in errno form.
*/
@@ -1043,6 +1272,15 @@ int z8530_init(struct z8530_dev *dev)
EXPORT_SYMBOL(z8530_init);
+/**
+ * z8530_shutdown:
+ * @dev: The Z8530 chip to shutdown
+ *
+ * We set the interrupt handlers to silence any interrupts. We then
+ * reset the chip and wait 100uS to be sure the reset completed. Just
+ * in case the caller then tries to do stuff.
+ */
+
int z8530_shutdown(struct z8530_dev *dev)
{
/* Reset the chip */
@@ -1055,9 +1293,15 @@ int z8530_shutdown(struct z8530_dev *dev)
EXPORT_SYMBOL(z8530_shutdown);
-/*
- * Load a Z8530 channel up from the system data
- * We use +16 to indicate the 'prime' registers
+/**
+ * z8530_channel_load:
+ * @c: Z8530 channel to configure
+ * @rtable: Table of register, value pairs
+ * FIXME: ioctl to allow user uploaded tables
+ *
+ * Load a Z8530 channel up from the system data> We use +16 to
+ * indicate the 'prime' registers. The value 255 terminates the
+ * table
*/
int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
@@ -1088,8 +1332,16 @@ int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
EXPORT_SYMBOL(z8530_channel_load);
-/*
- * Higher level shovelling - transmit chains
+/**
+ * z8530_tx_begin:
+ * @c: The Z8530 channel to kick
+ *
+ * This is the speed sensitive side of transmission. If we are called
+ * and no buffer is being transmitted we commence the next buffer. If
+ * nothing is queued we idle the sync.
+ *
+ * Note: We are handling this code path in the interrupt path, keep it
+ * fast or bad things will happen.
*/
static void z8530_tx_begin(struct z8530_channel *c)
@@ -1102,7 +1354,7 @@ static void z8530_tx_begin(struct z8530_channel *c)
c->tx_next_skb=NULL;
c->tx_ptr=c->tx_next_ptr;
- mark_bh(NET_BH);
+ netif_wake_queue(c->netdevice);
if(c->tx_skb==NULL)
{
/* Idle on */
@@ -1176,7 +1428,15 @@ static void z8530_tx_begin(struct z8530_channel *c)
}
}
}
-
+
+/**
+ * z8530_tx_done:
+ * @c: The channel that completed a transmit.
+ *
+ * This is called when we complete a packet send. We wake the queue,
+ * start the next packet going and then free the buffer of the existing
+ * packet. This code is fairly timing sensitive.
+ */
static void z8530_tx_done(struct z8530_channel *c)
{
@@ -1184,7 +1444,7 @@ static void z8530_tx_done(struct z8530_channel *c)
struct sk_buff *skb;
spin_lock_irqsave(&z8530_buffer_lock, flags);
- c->netdevice->tbusy=0;
+ netif_wake_queue(c->netdevice);
/* Actually this can happen.*/
if(c->tx_skb==NULL)
{
@@ -1197,11 +1457,16 @@ static void z8530_tx_done(struct z8530_channel *c)
spin_unlock_irqrestore(&z8530_buffer_lock, flags);
c->stats.tx_packets++;
c->stats.tx_bytes+=skb->len;
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
}
-/*
- * Higher level shovelling - receive chains
+/**
+ * z8530_null_rx:
+ * @c: The channel the packet arrived on
+ * @skb: The buffer
+ *
+ * We point the receive handler at this function when idle. Instead
+ * of syncppp processing the frames we get to throw them away.
*/
void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
@@ -1211,6 +1476,17 @@ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
EXPORT_SYMBOL(z8530_null_rx);
+/**
+ * z8530_rx_done:
+ * @c: The channel that completed a receive
+ *
+ * A new packet is complete. Our goal here is to get back into receive
+ * mode as fast as possible. On the Z85230 we could change to using
+ * ESCC mode, but on the older chips we have no choice. We flip to the
+ * new buffer immediately in DMA mode so that the DMA of the next
+ * frame can occur while we are copying the previous buffer to an sk_buff
+ */
+
static void z8530_rx_done(struct z8530_channel *c)
{
struct sk_buff *skb;
@@ -1265,7 +1541,7 @@ static void z8530_rx_done(struct z8530_channel *c)
else
/* Can't occur as we dont reenable the DMA irq until
after the flip is done */
- printk("DMA flip overrun!\n");
+ printk(KERN_WARNING "%s: DMA flip overrun!\n", c->netdevice->name);
release_dma_lock(flags);
@@ -1353,8 +1629,12 @@ static void z8530_rx_done(struct z8530_channel *c)
}
}
-/*
- * Cannot DMA over a 64K boundary on a PC
+/**
+ * spans_boundary:
+ * @skb: The buffer to check
+ *
+ * Returns true if the buffer cross a DMA boundary on a PC. The poor
+ * thing can only DMA within a 64K block not across the edges of it.
*/
extern inline int spans_boundary(struct sk_buff *skb)
@@ -1369,7 +1649,11 @@ extern inline int spans_boundary(struct sk_buff *skb)
return 0;
}
-/*
+/**
+ * z8530_queue_xmit:
+ * @c: The channel to use
+ * @skb: The packet to kick down the channel
+ *
* Queue a packet for transmission. Because we have rather
* hard to hit interrupt latencies for the Z85230 per packet
* even in DMA mode we do the flip to DMA buffer if needed here
@@ -1379,9 +1663,10 @@ extern inline int spans_boundary(struct sk_buff *skb)
int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
{
unsigned long flags;
+
+ netif_stop_queue(c->netdevice);
if(c->tx_next_skb)
{
- skb->dev->tbusy=1;
return 1;
}
@@ -1414,11 +1699,21 @@ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
spin_lock_irqsave(&z8530_buffer_lock, flags);
z8530_tx_begin(c);
spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+
+ netif_wake_queue(c->netdevice);
return 0;
}
EXPORT_SYMBOL(z8530_queue_xmit);
+/**
+ * z8530_get_stats:
+ * @c: The channel to use
+ *
+ * Get the statistics block. We keep the statistics in software as
+ * the chip doesn't do it for us.
+ */
+
struct net_device_stats *z8530_get_stats(struct z8530_channel *c)
{
return &c->stats;