mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1641 lines
39 KiB
1641 lines
39 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* (c) Copyright 1998 Alan Cox <[email protected]> |
|
* (c) Copyright 2000, 2001 Red Hat Inc |
|
* |
|
* Development of this driver was funded by Equiinet Ltd |
|
* http://www.equiinet.com |
|
* |
|
* ChangeLog: |
|
* |
|
* Asynchronous mode dropped for 2.2. For 2.5 we will attempt the |
|
* unification of all the Z85x30 asynchronous drivers for real. |
|
* |
|
* DMA now uses get_free_page as kmalloc buffers may span a 64K |
|
* boundary. |
|
* |
|
* Modified for SMP safety and SMP locking by Alan Cox |
|
* <[email protected]> |
|
* |
|
* Performance |
|
* |
|
* Z85230: |
|
* Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud |
|
* X.25 is not unrealistic on all machines. DMA mode can in theory |
|
* handle T1/E1 quite nicely. In practice the limit seems to be about |
|
* 512Kbit->1Mbit depending on motherboard. |
|
* |
|
* Z85C30: |
|
* 64K will take DMA, 9600 baud X.25 should be ok. |
|
* |
|
* Z8530: |
|
* Synchronous mode without DMA is unlikely to pass about 2400 baud. |
|
*/ |
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|
|
|
#include <linux/module.h> |
|
#include <linux/kernel.h> |
|
#include <linux/mm.h> |
|
#include <linux/net.h> |
|
#include <linux/skbuff.h> |
|
#include <linux/netdevice.h> |
|
#include <linux/if_arp.h> |
|
#include <linux/delay.h> |
|
#include <linux/hdlc.h> |
|
#include <linux/ioport.h> |
|
#include <linux/init.h> |
|
#include <linux/gfp.h> |
|
#include <asm/dma.h> |
|
#include <asm/io.h> |
|
#define RT_LOCK |
|
#define RT_UNLOCK |
|
#include <linux/spinlock.h> |
|
|
|
#include "z85230.h" |
|
|
|
/** |
|
* z8530_read_port - Architecture specific interface function |
|
* @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. |
|
*/ |
|
|
|
static 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 ! */ |
|
udelay(5); |
|
return r; |
|
} |
|
|
|
/** |
|
* z8530_write_port - Architecture specific interface function |
|
* @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. |
|
*/ |
|
|
|
static inline void z8530_write_port(unsigned long p, u8 d) |
|
{ |
|
outb(d, Z8530_PORT_OF(p)); |
|
if (p & Z8530_PORT_SLEEP) |
|
udelay(5); |
|
} |
|
|
|
static void z8530_rx_done(struct z8530_channel *c); |
|
static void z8530_tx_done(struct z8530_channel *c); |
|
|
|
/** |
|
* read_zsreg - Read a register from a Z85230 |
|
* @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. The caller must hold the lock |
|
*/ |
|
|
|
static inline u8 read_zsreg(struct z8530_channel *c, u8 reg) |
|
{ |
|
if (reg) |
|
z8530_write_port(c->ctrlio, reg); |
|
return z8530_read_port(c->ctrlio); |
|
} |
|
|
|
/** |
|
* read_zsdata - Read the data port of a Z8530 channel |
|
* @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. |
|
*/ |
|
|
|
static inline u8 read_zsdata(struct z8530_channel *c) |
|
{ |
|
u8 r; |
|
|
|
r = z8530_read_port(c->dataio); |
|
return r; |
|
} |
|
|
|
/** |
|
* write_zsreg - Write to a Z8530 channel register |
|
* @c: The Z8530 channel |
|
* @reg: Register number |
|
* @val: Value to write |
|
* |
|
* Write a value to an indexed register. The caller must hold the lock |
|
* to honour the irritating delay rules. We know about register 0 |
|
* being fast to access. |
|
* |
|
* Assumes c->lock is held. |
|
*/ |
|
static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) |
|
{ |
|
if (reg) |
|
z8530_write_port(c->ctrlio, reg); |
|
z8530_write_port(c->ctrlio, val); |
|
} |
|
|
|
/** |
|
* write_zsctrl - Write to a Z8530 control register |
|
* @c: The Z8530 channel |
|
* @val: Value to write |
|
* |
|
* Write directly to the control register on the Z8530 |
|
*/ |
|
|
|
static inline void write_zsctrl(struct z8530_channel *c, u8 val) |
|
{ |
|
z8530_write_port(c->ctrlio, val); |
|
} |
|
|
|
/** |
|
* write_zsdata - Write to a Z8530 control register |
|
* @c: The Z8530 channel |
|
* @val: Value to write |
|
* |
|
* Write directly to the data register on the Z8530 |
|
*/ |
|
static inline void write_zsdata(struct z8530_channel *c, u8 val) |
|
{ |
|
z8530_write_port(c->dataio, val); |
|
} |
|
|
|
/* Register loading parameters for a dead port |
|
*/ |
|
|
|
u8 z8530_dead_port[] = { |
|
255 |
|
}; |
|
EXPORT_SYMBOL(z8530_dead_port); |
|
|
|
/* Register loading parameters for currently supported circuit types |
|
*/ |
|
|
|
/* Data clocked by telco end. This is the correct data for the UK |
|
* "kilostream" service, and most other similar services. |
|
*/ |
|
|
|
u8 z8530_hdlc_kilostream[] = { |
|
4, SYNC_ENAB | SDLC | X1CLK, |
|
2, 0, /* No vector */ |
|
1, 0, |
|
3, ENT_HM | RxCRC_ENAB | Rx8, |
|
5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR, |
|
9, 0, /* Disable interrupts */ |
|
6, 0xFF, |
|
7, FLAG, |
|
10, ABUNDER | NRZ | CRCPS,/*MARKIDLE ??*/ |
|
11, TCTRxCP, |
|
14, DISDPLL, |
|
15, DCDIE | SYNCIE | CTSIE | TxUIE | BRKIE, |
|
1, EXT_INT_ENAB | TxINT_ENAB | INT_ALL_Rx, |
|
9, NV | MIE | NORESET, |
|
255 |
|
}; |
|
EXPORT_SYMBOL(z8530_hdlc_kilostream); |
|
|
|
/* As above but for enhanced chips. |
|
*/ |
|
|
|
u8 z8530_hdlc_kilostream_85230[] = { |
|
4, SYNC_ENAB | SDLC | X1CLK, |
|
2, 0, /* No vector */ |
|
1, 0, |
|
3, ENT_HM | RxCRC_ENAB | Rx8, |
|
5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR, |
|
9, 0, /* Disable interrupts */ |
|
6, 0xFF, |
|
7, FLAG, |
|
10, ABUNDER | NRZ | CRCPS, /* MARKIDLE?? */ |
|
11, TCTRxCP, |
|
14, DISDPLL, |
|
15, DCDIE | SYNCIE | CTSIE | TxUIE | BRKIE, |
|
1, EXT_INT_ENAB | TxINT_ENAB | INT_ALL_Rx, |
|
9, NV | MIE | NORESET, |
|
23, 3, /* Extended mode AUTO TX and EOM*/ |
|
|
|
255 |
|
}; |
|
EXPORT_SYMBOL(z8530_hdlc_kilostream_85230); |
|
|
|
/** |
|
* z8530_flush_fifo - Flush on chip RX 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) |
|
{ |
|
read_zsreg(c, R1); |
|
read_zsreg(c, R1); |
|
read_zsreg(c, R1); |
|
read_zsreg(c, R1); |
|
if (c->dev->type == Z85230) { |
|
read_zsreg(c, R1); |
|
read_zsreg(c, R1); |
|
read_zsreg(c, R1); |
|
read_zsreg(c, R1); |
|
} |
|
} |
|
|
|
/** |
|
* z8530_rtsdtr - Control the outgoing DTS/RTS line |
|
* @c: The Z8530 channel to control; |
|
* @set: 1 to set, 0 to clear |
|
* |
|
* Sets or clears DTR/RTS on the requested line. All locking is handled |
|
* by 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) |
|
{ |
|
if (set) |
|
c->regs[5] |= (RTS | DTR); |
|
else |
|
c->regs[5] &= ~(RTS | DTR); |
|
write_zsreg(c, R5, c->regs[5]); |
|
} |
|
|
|
/** |
|
* z8530_rx - Handle a PIO receive event |
|
* @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 |
|
* (eg to ever clock 64kbits on a sparc ;)). |
|
* |
|
* The RT_LOCK macros don't do anything now. Keep the code covered |
|
* by them as short as possible in all circumstances - clocks cost |
|
* baud. The interrupt handler is assumed to be atomic w.r.t. to |
|
* 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. The DMA mode assumes PCI like |
|
* ISA DMA |
|
* |
|
* Called with the device lock held |
|
*/ |
|
|
|
static void z8530_rx(struct z8530_channel *c) |
|
{ |
|
u8 ch, stat; |
|
|
|
while (1) { |
|
/* FIFO empty ? */ |
|
if (!(read_zsreg(c, R0) & 1)) |
|
break; |
|
ch = read_zsdata(c); |
|
stat = read_zsreg(c, R1); |
|
|
|
/* Overrun ? |
|
*/ |
|
if (c->count < c->max) { |
|
*c->dptr++ = ch; |
|
c->count++; |
|
} |
|
|
|
if (stat & END_FR) { |
|
/* Error ? |
|
*/ |
|
if (stat & (Rx_OVR | CRC_ERR)) { |
|
/* Rewind the buffer and return */ |
|
if (c->skb) |
|
c->dptr = c->skb->data; |
|
c->count = 0; |
|
if (stat & Rx_OVR) { |
|
pr_warn("%s: overrun\n", c->dev->name); |
|
c->rx_overrun++; |
|
} |
|
if (stat & CRC_ERR) { |
|
c->rx_crc_err++; |
|
/* printk("crc error\n"); */ |
|
} |
|
/* Shove the frame upstream */ |
|
} else { |
|
/* Drop the lock for RX processing, or |
|
* there are deadlocks |
|
*/ |
|
z8530_rx_done(c); |
|
write_zsctrl(c, RES_Rx_CRC); |
|
} |
|
} |
|
} |
|
/* Clear irq |
|
*/ |
|
write_zsctrl(c, ERR_RES); |
|
write_zsctrl(c, RES_H_IUS); |
|
} |
|
|
|
/** |
|
* z8530_tx - Handle a PIO transmit event |
|
* @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) |
|
{ |
|
while (c->txcount) { |
|
/* FIFO full ? */ |
|
if (!(read_zsreg(c, R0) & 4)) |
|
return; |
|
c->txcount--; |
|
/* Shovel out the byte |
|
*/ |
|
write_zsreg(c, R8, *c->tx_ptr++); |
|
write_zsctrl(c, RES_H_IUS); |
|
/* We are about to underflow */ |
|
if (c->txcount == 0) { |
|
write_zsctrl(c, RES_EOM_L); |
|
write_zsreg(c, R10, c->regs[10] & ~ABUNDER); |
|
} |
|
} |
|
|
|
/* End of frame TX - fire another one |
|
*/ |
|
|
|
write_zsctrl(c, RES_Tx_P); |
|
|
|
z8530_tx_done(c); |
|
write_zsctrl(c, RES_H_IUS); |
|
} |
|
|
|
/** |
|
* z8530_status - Handle a PIO status exception |
|
* @chan: Z8530 channel to process |
|
* |
|
* A status event occurred 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. |
|
*/ |
|
|
|
static void z8530_status(struct z8530_channel *chan) |
|
{ |
|
u8 status, altered; |
|
|
|
status = read_zsreg(chan, R0); |
|
altered = chan->status ^ status; |
|
|
|
chan->status = status; |
|
|
|
if (status & TxEOM) { |
|
/* printk("%s: Tx underrun.\n", chan->dev->name); */ |
|
chan->netdevice->stats.tx_fifo_errors++; |
|
write_zsctrl(chan, ERR_RES); |
|
z8530_tx_done(chan); |
|
} |
|
|
|
if (altered & chan->dcdcheck) { |
|
if (status & chan->dcdcheck) { |
|
pr_info("%s: DCD raised\n", chan->dev->name); |
|
write_zsreg(chan, R3, chan->regs[3] | RxENABLE); |
|
if (chan->netdevice) |
|
netif_carrier_on(chan->netdevice); |
|
} else { |
|
pr_info("%s: DCD lost\n", chan->dev->name); |
|
write_zsreg(chan, R3, chan->regs[3] & ~RxENABLE); |
|
z8530_flush_fifo(chan); |
|
if (chan->netdevice) |
|
netif_carrier_off(chan->netdevice); |
|
} |
|
} |
|
write_zsctrl(chan, RES_EXT_INT); |
|
write_zsctrl(chan, RES_H_IUS); |
|
} |
|
|
|
struct z8530_irqhandler z8530_sync = { |
|
.rx = z8530_rx, |
|
.tx = z8530_tx, |
|
.status = z8530_status, |
|
}; |
|
EXPORT_SYMBOL(z8530_sync); |
|
|
|
/** |
|
* z8530_dma_rx - Handle a DMA RX event |
|
* @chan: Channel to handle |
|
* |
|
* Non bus mastering DMA interfaces for the Z8x30 devices. This |
|
* 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) |
|
{ |
|
if (chan->rxdma_on) { |
|
/* Special condition check only */ |
|
u8 status; |
|
|
|
read_zsreg(chan, R7); |
|
read_zsreg(chan, R6); |
|
|
|
status = read_zsreg(chan, R1); |
|
|
|
if (status & END_FR) |
|
z8530_rx_done(chan); /* Fire up the next one */ |
|
|
|
write_zsctrl(chan, ERR_RES); |
|
write_zsctrl(chan, RES_H_IUS); |
|
} else { |
|
/* DMA is off right now, drain the slow way */ |
|
z8530_rx(chan); |
|
} |
|
} |
|
|
|
/** |
|
* z8530_dma_tx - Handle a DMA TX event |
|
* @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) { |
|
pr_warn("Hey who turned the DMA off?\n"); |
|
z8530_tx(chan); |
|
return; |
|
} |
|
/* This shouldn't occur in DMA mode */ |
|
pr_err("DMA tx - bogus event!\n"); |
|
z8530_tx(chan); |
|
} |
|
|
|
/** |
|
* z8530_dma_status - Handle a DMA status exception |
|
* @chan: Z8530 channel to process |
|
* |
|
* A status event occurred 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. |
|
* |
|
*/ |
|
static void z8530_dma_status(struct z8530_channel *chan) |
|
{ |
|
u8 status, altered; |
|
|
|
status = read_zsreg(chan, R0); |
|
altered = chan->status ^ status; |
|
|
|
chan->status = status; |
|
|
|
if (chan->dma_tx) { |
|
if (status & TxEOM) { |
|
unsigned long flags; |
|
|
|
flags = claim_dma_lock(); |
|
disable_dma(chan->txdma); |
|
clear_dma_ff(chan->txdma); |
|
chan->txdma_on = 0; |
|
release_dma_lock(flags); |
|
z8530_tx_done(chan); |
|
} |
|
} |
|
|
|
if (altered & chan->dcdcheck) { |
|
if (status & chan->dcdcheck) { |
|
pr_info("%s: DCD raised\n", chan->dev->name); |
|
write_zsreg(chan, R3, chan->regs[3] | RxENABLE); |
|
if (chan->netdevice) |
|
netif_carrier_on(chan->netdevice); |
|
} else { |
|
pr_info("%s: DCD lost\n", chan->dev->name); |
|
write_zsreg(chan, R3, chan->regs[3] & ~RxENABLE); |
|
z8530_flush_fifo(chan); |
|
if (chan->netdevice) |
|
netif_carrier_off(chan->netdevice); |
|
} |
|
} |
|
|
|
write_zsctrl(chan, RES_EXT_INT); |
|
write_zsctrl(chan, RES_H_IUS); |
|
} |
|
|
|
static struct z8530_irqhandler z8530_dma_sync = { |
|
.rx = z8530_dma_rx, |
|
.tx = z8530_dma_tx, |
|
.status = z8530_dma_status, |
|
}; |
|
|
|
static struct z8530_irqhandler z8530_txdma_sync = { |
|
.rx = z8530_rx, |
|
.tx = z8530_dma_tx, |
|
.status = z8530_dma_status, |
|
}; |
|
|
|
/** |
|
* z8530_rx_clear - Handle RX events from a stopped chip |
|
* @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. |
|
*/ |
|
|
|
static void z8530_rx_clear(struct z8530_channel *c) |
|
{ |
|
/* Data and status bytes |
|
*/ |
|
u8 stat; |
|
|
|
read_zsdata(c); |
|
stat = read_zsreg(c, R1); |
|
|
|
if (stat & END_FR) |
|
write_zsctrl(c, RES_Rx_CRC); |
|
/* Clear irq |
|
*/ |
|
write_zsctrl(c, ERR_RES); |
|
write_zsctrl(c, RES_H_IUS); |
|
} |
|
|
|
/** |
|
* z8530_tx_clear - Handle TX events from a stopped chip |
|
* @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 - Handle status events from a stopped chip |
|
* @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); |
|
|
|
if (status & TxEOM) |
|
write_zsctrl(chan, ERR_RES); |
|
write_zsctrl(chan, RES_EXT_INT); |
|
write_zsctrl(chan, RES_H_IUS); |
|
} |
|
|
|
struct z8530_irqhandler z8530_nop = { |
|
.rx = z8530_rx_clear, |
|
.tx = z8530_tx_clear, |
|
.status = z8530_status_clear, |
|
}; |
|
EXPORT_SYMBOL(z8530_nop); |
|
|
|
/** |
|
* z8530_interrupt - Handle an interrupt from a Z8530 |
|
* @irq: Interrupt number |
|
* @dev_id: The Z8530 device that is interrupting. |
|
* |
|
* 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. |
|
* |
|
* Locking is done for the handlers. Note that locking is done |
|
* at the chip level (the 5uS delay issue is per chip not per |
|
* channel). c->lock for both channels points to dev->lock |
|
*/ |
|
|
|
irqreturn_t z8530_interrupt(int irq, void *dev_id) |
|
{ |
|
struct z8530_dev *dev = dev_id; |
|
u8 intr; |
|
static volatile int locker=0; |
|
int work = 0; |
|
struct z8530_irqhandler *irqs; |
|
|
|
if (locker) { |
|
pr_err("IRQ re-enter\n"); |
|
return IRQ_NONE; |
|
} |
|
locker = 1; |
|
|
|
spin_lock(&dev->lock); |
|
|
|
while (++work < 5000) { |
|
intr = read_zsreg(&dev->chanA, R3); |
|
if (!(intr & |
|
(CHARxIP | CHATxIP | CHAEXT | CHBRxIP | CHBTxIP | CHBEXT))) |
|
break; |
|
|
|
/* This holds the IRQ status. On the 8530 you must read it |
|
* from chan A even though it applies to the whole chip |
|
*/ |
|
|
|
/* Now walk the chip and see what it is wanting - it may be |
|
* an IRQ for someone else remember |
|
*/ |
|
|
|
irqs = dev->chanA.irqs; |
|
|
|
if (intr & (CHARxIP | CHATxIP | CHAEXT)) { |
|
if (intr & CHARxIP) |
|
irqs->rx(&dev->chanA); |
|
if (intr & CHATxIP) |
|
irqs->tx(&dev->chanA); |
|
if (intr & CHAEXT) |
|
irqs->status(&dev->chanA); |
|
} |
|
|
|
irqs = dev->chanB.irqs; |
|
|
|
if (intr & (CHBRxIP | CHBTxIP | CHBEXT)) { |
|
if (intr & CHBRxIP) |
|
irqs->rx(&dev->chanB); |
|
if (intr & CHBTxIP) |
|
irqs->tx(&dev->chanB); |
|
if (intr & CHBEXT) |
|
irqs->status(&dev->chanB); |
|
} |
|
} |
|
spin_unlock(&dev->lock); |
|
if (work == 5000) |
|
pr_err("%s: interrupt jammed - abort(0x%X)!\n", |
|
dev->name, intr); |
|
/* Ok all done */ |
|
locker = 0; |
|
return IRQ_HANDLED; |
|
} |
|
EXPORT_SYMBOL(z8530_interrupt); |
|
|
|
static const u8 reg_init[16] = { |
|
0, 0, 0, 0, |
|
0, 0, 0, 0, |
|
0, 0, 0, 0, |
|
0x55, 0, 0, 0 |
|
}; |
|
|
|
/** |
|
* z8530_sync_open - Open a Z8530 channel for PIO |
|
* @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) |
|
{ |
|
unsigned long flags; |
|
|
|
spin_lock_irqsave(c->lock, flags); |
|
|
|
c->sync = 1; |
|
c->mtu = dev->mtu + 64; |
|
c->count = 0; |
|
c->skb = NULL; |
|
c->skb2 = NULL; |
|
c->irqs = &z8530_sync; |
|
|
|
/* This loads the double buffer up */ |
|
z8530_rx_done(c); /* Load the frame ring */ |
|
z8530_rx_done(c); /* Load the backup frame */ |
|
z8530_rtsdtr(c, 1); |
|
c->dma_tx = 0; |
|
c->regs[R1] |= TxINT_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
write_zsreg(c, R3, c->regs[R3] | RxENABLE); |
|
|
|
spin_unlock_irqrestore(c->lock, flags); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_sync_open); |
|
|
|
/** |
|
* z8530_sync_close - Close a PIO Z8530 channel |
|
* @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; |
|
unsigned long flags; |
|
|
|
spin_lock_irqsave(c->lock, flags); |
|
c->irqs = &z8530_nop; |
|
c->max = 0; |
|
c->sync = 0; |
|
|
|
chk = read_zsreg(c, R0); |
|
write_zsreg(c, R3, c->regs[R3]); |
|
z8530_rtsdtr(c, 0); |
|
|
|
spin_unlock_irqrestore(c->lock, flags); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_sync_close); |
|
|
|
/** |
|
* z8530_sync_dma_open - Open a Z8530 for DMA I/O |
|
* @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 cflags, dflags; |
|
|
|
c->sync = 1; |
|
c->mtu = dev->mtu + 64; |
|
c->count = 0; |
|
c->skb = NULL; |
|
c->skb2 = NULL; |
|
|
|
/* Load the DMA interfaces up |
|
*/ |
|
c->rxdma_on = 0; |
|
c->txdma_on = 0; |
|
|
|
/* Allocate the DMA flip buffers. Limit by page size. |
|
* Everyone runs 1500 mtu or less on wan links so this |
|
* should be fine. |
|
*/ |
|
|
|
if (c->mtu > PAGE_SIZE / 2) |
|
return -EMSGSIZE; |
|
|
|
c->rx_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
|
if (!c->rx_buf[0]) |
|
return -ENOBUFS; |
|
c->rx_buf[1] = c->rx_buf[0] + PAGE_SIZE / 2; |
|
|
|
c->tx_dma_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
|
if (!c->tx_dma_buf[0]) { |
|
free_page((unsigned long)c->rx_buf[0]); |
|
c->rx_buf[0] = NULL; |
|
return -ENOBUFS; |
|
} |
|
c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE / 2; |
|
|
|
c->tx_dma_used = 0; |
|
c->dma_tx = 1; |
|
c->dma_num = 0; |
|
c->dma_ready = 1; |
|
|
|
/* Enable DMA control mode |
|
*/ |
|
|
|
spin_lock_irqsave(c->lock, cflags); |
|
|
|
/* TX DMA via DIR/REQ |
|
*/ |
|
|
|
c->regs[R14] |= DTRREQ; |
|
write_zsreg(c, R14, c->regs[R14]); |
|
|
|
c->regs[R1] &= ~TxINT_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
|
|
/* RX DMA via W/Req |
|
*/ |
|
|
|
c->regs[R1] |= WT_FN_RDYFN; |
|
c->regs[R1] |= WT_RDY_RT; |
|
c->regs[R1] |= INT_ERR_Rx; |
|
c->regs[R1] &= ~TxINT_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
c->regs[R1] |= WT_RDY_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
|
|
/* DMA interrupts |
|
*/ |
|
|
|
/* Set up the DMA configuration |
|
*/ |
|
|
|
dflags = claim_dma_lock(); |
|
|
|
disable_dma(c->rxdma); |
|
clear_dma_ff(c->rxdma); |
|
set_dma_mode(c->rxdma, DMA_MODE_READ | 0x10); |
|
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0])); |
|
set_dma_count(c->rxdma, c->mtu); |
|
enable_dma(c->rxdma); |
|
|
|
disable_dma(c->txdma); |
|
clear_dma_ff(c->txdma); |
|
set_dma_mode(c->txdma, DMA_MODE_WRITE); |
|
disable_dma(c->txdma); |
|
|
|
release_dma_lock(dflags); |
|
|
|
/* Select the DMA interrupt handlers |
|
*/ |
|
|
|
c->rxdma_on = 1; |
|
c->txdma_on = 1; |
|
c->tx_dma_used = 1; |
|
|
|
c->irqs = &z8530_dma_sync; |
|
z8530_rtsdtr(c, 1); |
|
write_zsreg(c, R3, c->regs[R3] | RxENABLE); |
|
|
|
spin_unlock_irqrestore(c->lock, cflags); |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_sync_dma_open); |
|
|
|
/** |
|
* z8530_sync_dma_close - Close down DMA I/O |
|
* @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; |
|
unsigned long flags; |
|
|
|
c->irqs = &z8530_nop; |
|
c->max = 0; |
|
c->sync = 0; |
|
|
|
/* Disable the PC DMA channels |
|
*/ |
|
|
|
flags = claim_dma_lock(); |
|
disable_dma(c->rxdma); |
|
clear_dma_ff(c->rxdma); |
|
|
|
c->rxdma_on = 0; |
|
|
|
disable_dma(c->txdma); |
|
clear_dma_ff(c->txdma); |
|
release_dma_lock(flags); |
|
|
|
c->txdma_on = 0; |
|
c->tx_dma_used = 0; |
|
|
|
spin_lock_irqsave(c->lock, flags); |
|
|
|
/* Disable DMA control mode |
|
*/ |
|
|
|
c->regs[R1] &= ~WT_RDY_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
c->regs[R1] &= ~(WT_RDY_RT | WT_FN_RDYFN | INT_ERR_Rx); |
|
c->regs[R1] |= INT_ALL_Rx; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
c->regs[R14] &= ~DTRREQ; |
|
write_zsreg(c, R14, c->regs[R14]); |
|
|
|
if (c->rx_buf[0]) { |
|
free_page((unsigned long)c->rx_buf[0]); |
|
c->rx_buf[0] = NULL; |
|
} |
|
if (c->tx_dma_buf[0]) { |
|
free_page((unsigned long)c->tx_dma_buf[0]); |
|
c->tx_dma_buf[0] = NULL; |
|
} |
|
chk = read_zsreg(c, R0); |
|
write_zsreg(c, R3, c->regs[R3]); |
|
z8530_rtsdtr(c, 0); |
|
|
|
spin_unlock_irqrestore(c->lock, flags); |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_sync_dma_close); |
|
|
|
/** |
|
* z8530_sync_txdma_open - Open a Z8530 for TX driven DMA |
|
* @dev: The network device to attach |
|
* @c: The Z8530 channel to configure in sync DMA mode. |
|
* |
|
* Set up a Z85x30 device for synchronous DMA transmission. 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 cflags, dflags; |
|
|
|
printk("Opening sync interface for TX-DMA\n"); |
|
c->sync = 1; |
|
c->mtu = dev->mtu + 64; |
|
c->count = 0; |
|
c->skb = NULL; |
|
c->skb2 = NULL; |
|
|
|
/* Allocate the DMA flip buffers. Limit by page size. |
|
* Everyone runs 1500 mtu or less on wan links so this |
|
* should be fine. |
|
*/ |
|
|
|
if (c->mtu > PAGE_SIZE / 2) |
|
return -EMSGSIZE; |
|
|
|
c->tx_dma_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
|
if (!c->tx_dma_buf[0]) |
|
return -ENOBUFS; |
|
|
|
c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE / 2; |
|
|
|
spin_lock_irqsave(c->lock, cflags); |
|
|
|
/* Load the PIO receive ring |
|
*/ |
|
|
|
z8530_rx_done(c); |
|
z8530_rx_done(c); |
|
|
|
/* Load the DMA interfaces up |
|
*/ |
|
|
|
c->rxdma_on = 0; |
|
c->txdma_on = 0; |
|
|
|
c->tx_dma_used = 0; |
|
c->dma_num = 0; |
|
c->dma_ready = 1; |
|
c->dma_tx = 1; |
|
|
|
/* Enable DMA control mode |
|
*/ |
|
|
|
/* TX DMA via DIR/REQ |
|
*/ |
|
c->regs[R14] |= DTRREQ; |
|
write_zsreg(c, R14, c->regs[R14]); |
|
|
|
c->regs[R1] &= ~TxINT_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
|
|
/* Set up the DMA configuration |
|
*/ |
|
|
|
dflags = claim_dma_lock(); |
|
|
|
disable_dma(c->txdma); |
|
clear_dma_ff(c->txdma); |
|
set_dma_mode(c->txdma, DMA_MODE_WRITE); |
|
disable_dma(c->txdma); |
|
|
|
release_dma_lock(dflags); |
|
|
|
/* Select the DMA interrupt handlers |
|
*/ |
|
|
|
c->rxdma_on = 0; |
|
c->txdma_on = 1; |
|
c->tx_dma_used = 1; |
|
|
|
c->irqs = &z8530_txdma_sync; |
|
z8530_rtsdtr(c, 1); |
|
write_zsreg(c, R3, c->regs[R3] | RxENABLE); |
|
spin_unlock_irqrestore(c->lock, cflags); |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_sync_txdma_open); |
|
|
|
/** |
|
* z8530_sync_txdma_close - Close down a TX driven DMA channel |
|
* @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 dflags, cflags; |
|
u8 chk; |
|
|
|
spin_lock_irqsave(c->lock, cflags); |
|
|
|
c->irqs = &z8530_nop; |
|
c->max = 0; |
|
c->sync = 0; |
|
|
|
/* Disable the PC DMA channels |
|
*/ |
|
|
|
dflags = claim_dma_lock(); |
|
|
|
disable_dma(c->txdma); |
|
clear_dma_ff(c->txdma); |
|
c->txdma_on = 0; |
|
c->tx_dma_used = 0; |
|
|
|
release_dma_lock(dflags); |
|
|
|
/* Disable DMA control mode |
|
*/ |
|
|
|
c->regs[R1] &= ~WT_RDY_ENAB; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
c->regs[R1] &= ~(WT_RDY_RT | WT_FN_RDYFN | INT_ERR_Rx); |
|
c->regs[R1] |= INT_ALL_Rx; |
|
write_zsreg(c, R1, c->regs[R1]); |
|
c->regs[R14] &= ~DTRREQ; |
|
write_zsreg(c, R14, c->regs[R14]); |
|
|
|
if (c->tx_dma_buf[0]) { |
|
free_page((unsigned long)c->tx_dma_buf[0]); |
|
c->tx_dma_buf[0] = NULL; |
|
} |
|
chk = read_zsreg(c, R0); |
|
write_zsreg(c, R3, c->regs[R3]); |
|
z8530_rtsdtr(c, 0); |
|
|
|
spin_unlock_irqrestore(c->lock, cflags); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_sync_txdma_close); |
|
|
|
/* Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny |
|
* it exists... |
|
*/ |
|
static const char * const z8530_type_name[] = { |
|
"Z8530", |
|
"Z85C30", |
|
"Z85230" |
|
}; |
|
|
|
/** |
|
* z8530_describe - Uniformly describe a Z8530 port |
|
* @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 isn't 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) |
|
{ |
|
pr_info("%s: %s found at %s 0x%lX, IRQ %d\n", |
|
dev->name, |
|
z8530_type_name[dev->type], |
|
mapping, |
|
Z8530_PORT_OF(io), |
|
dev->irq); |
|
} |
|
EXPORT_SYMBOL(z8530_describe); |
|
|
|
/* Locked operation part of the z8530 init code |
|
*/ |
|
static inline int do_z8530_init(struct z8530_dev *dev) |
|
{ |
|
/* NOP the interrupt handlers first - we might get a |
|
* floating IRQ transition when we reset the chip |
|
*/ |
|
dev->chanA.irqs = &z8530_nop; |
|
dev->chanB.irqs = &z8530_nop; |
|
dev->chanA.dcdcheck = DCD; |
|
dev->chanB.dcdcheck = DCD; |
|
|
|
/* Reset the chip */ |
|
write_zsreg(&dev->chanA, R9, 0xC0); |
|
udelay(200); |
|
/* Now check its valid */ |
|
write_zsreg(&dev->chanA, R12, 0xAA); |
|
if (read_zsreg(&dev->chanA, R12) != 0xAA) |
|
return -ENODEV; |
|
write_zsreg(&dev->chanA, R12, 0x55); |
|
if (read_zsreg(&dev->chanA, R12) != 0x55) |
|
return -ENODEV; |
|
|
|
dev->type = Z8530; |
|
|
|
/* See the application note. |
|
*/ |
|
|
|
write_zsreg(&dev->chanA, R15, 0x01); |
|
|
|
/* If we can set the low bit of R15 then |
|
* the chip is enhanced. |
|
*/ |
|
|
|
if (read_zsreg(&dev->chanA, R15) == 0x01) { |
|
/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */ |
|
/* Put a char in the fifo */ |
|
write_zsreg(&dev->chanA, R8, 0); |
|
if (read_zsreg(&dev->chanA, R0) & Tx_BUF_EMP) |
|
dev->type = Z85230; /* Has a FIFO */ |
|
else |
|
dev->type = Z85C30; /* Z85C30, 1 byte FIFO */ |
|
} |
|
|
|
/* The code assumes R7' and friends are |
|
* off. Use write_zsext() for these and keep |
|
* this bit clear. |
|
*/ |
|
|
|
write_zsreg(&dev->chanA, R15, 0); |
|
|
|
/* At this point it looks like the chip is behaving |
|
*/ |
|
|
|
memcpy(dev->chanA.regs, reg_init, 16); |
|
memcpy(dev->chanB.regs, reg_init, 16); |
|
|
|
return 0; |
|
} |
|
|
|
/** |
|
* z8530_init - Initialise a Z8530 device |
|
* @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. |
|
*/ |
|
|
|
int z8530_init(struct z8530_dev *dev) |
|
{ |
|
unsigned long flags; |
|
int ret; |
|
|
|
/* Set up the chip level lock */ |
|
spin_lock_init(&dev->lock); |
|
dev->chanA.lock = &dev->lock; |
|
dev->chanB.lock = &dev->lock; |
|
|
|
spin_lock_irqsave(&dev->lock, flags); |
|
ret = do_z8530_init(dev); |
|
spin_unlock_irqrestore(&dev->lock, flags); |
|
|
|
return ret; |
|
} |
|
EXPORT_SYMBOL(z8530_init); |
|
|
|
/** |
|
* z8530_shutdown - Shutdown a Z8530 device |
|
* @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. |
|
* |
|
* This is called without the lock held |
|
*/ |
|
int z8530_shutdown(struct z8530_dev *dev) |
|
{ |
|
unsigned long flags; |
|
/* Reset the chip */ |
|
|
|
spin_lock_irqsave(&dev->lock, flags); |
|
dev->chanA.irqs = &z8530_nop; |
|
dev->chanB.irqs = &z8530_nop; |
|
write_zsreg(&dev->chanA, R9, 0xC0); |
|
/* We must lock the udelay, the chip is offlimits here */ |
|
udelay(100); |
|
spin_unlock_irqrestore(&dev->lock, flags); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_shutdown); |
|
|
|
/** |
|
* z8530_channel_load - Load channel data |
|
* @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) |
|
{ |
|
unsigned long flags; |
|
|
|
spin_lock_irqsave(c->lock, flags); |
|
|
|
while (*rtable != 255) { |
|
int reg = *rtable++; |
|
|
|
if (reg > 0x0F) |
|
write_zsreg(c, R15, c->regs[15] | 1); |
|
write_zsreg(c, reg & 0x0F, *rtable); |
|
if (reg > 0x0F) |
|
write_zsreg(c, R15, c->regs[15] & ~1); |
|
c->regs[reg] = *rtable++; |
|
} |
|
c->rx_function = z8530_null_rx; |
|
c->skb = NULL; |
|
c->tx_skb = NULL; |
|
c->tx_next_skb = NULL; |
|
c->mtu = 1500; |
|
c->max = 0; |
|
c->count = 0; |
|
c->status = read_zsreg(c, R0); |
|
c->sync = 1; |
|
write_zsreg(c, R3, c->regs[R3] | RxENABLE); |
|
|
|
spin_unlock_irqrestore(c->lock, flags); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL(z8530_channel_load); |
|
|
|
/** |
|
* z8530_tx_begin - Begin packet transmission |
|
* @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. |
|
* |
|
* Called with the lock held. |
|
*/ |
|
|
|
static void z8530_tx_begin(struct z8530_channel *c) |
|
{ |
|
unsigned long flags; |
|
|
|
if (c->tx_skb) |
|
return; |
|
|
|
c->tx_skb = c->tx_next_skb; |
|
c->tx_next_skb = NULL; |
|
c->tx_ptr = c->tx_next_ptr; |
|
|
|
if (!c->tx_skb) { |
|
/* Idle on */ |
|
if (c->dma_tx) { |
|
flags = claim_dma_lock(); |
|
disable_dma(c->txdma); |
|
/* Check if we crapped out. |
|
*/ |
|
if (get_dma_residue(c->txdma)) { |
|
c->netdevice->stats.tx_dropped++; |
|
c->netdevice->stats.tx_fifo_errors++; |
|
} |
|
release_dma_lock(flags); |
|
} |
|
c->txcount = 0; |
|
} else { |
|
c->txcount = c->tx_skb->len; |
|
|
|
if (c->dma_tx) { |
|
/* FIXME. DMA is broken for the original 8530, |
|
* on the older parts we need to set a flag and |
|
* wait for a further TX interrupt to fire this |
|
* stage off |
|
*/ |
|
|
|
flags = claim_dma_lock(); |
|
disable_dma(c->txdma); |
|
|
|
/* These two are needed by the 8530/85C30 |
|
* and must be issued when idling. |
|
*/ |
|
if (c->dev->type != Z85230) { |
|
write_zsctrl(c, RES_Tx_CRC); |
|
write_zsctrl(c, RES_EOM_L); |
|
} |
|
write_zsreg(c, R10, c->regs[10] & ~ABUNDER); |
|
clear_dma_ff(c->txdma); |
|
set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); |
|
set_dma_count(c->txdma, c->txcount); |
|
enable_dma(c->txdma); |
|
release_dma_lock(flags); |
|
write_zsctrl(c, RES_EOM_L); |
|
write_zsreg(c, R5, c->regs[R5] | TxENAB); |
|
} else { |
|
/* ABUNDER off */ |
|
write_zsreg(c, R10, c->regs[10]); |
|
write_zsctrl(c, RES_Tx_CRC); |
|
|
|
while (c->txcount && (read_zsreg(c, R0) & Tx_BUF_EMP)) { |
|
write_zsreg(c, R8, *c->tx_ptr++); |
|
c->txcount--; |
|
} |
|
} |
|
} |
|
/* Since we emptied tx_skb we can ask for more |
|
*/ |
|
netif_wake_queue(c->netdevice); |
|
} |
|
|
|
/** |
|
* z8530_tx_done - TX complete callback |
|
* @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. |
|
* |
|
* Called with the register lock held. |
|
*/ |
|
|
|
static void z8530_tx_done(struct z8530_channel *c) |
|
{ |
|
struct sk_buff *skb; |
|
|
|
/* Actually this can happen.*/ |
|
if (!c->tx_skb) |
|
return; |
|
|
|
skb = c->tx_skb; |
|
c->tx_skb = NULL; |
|
z8530_tx_begin(c); |
|
c->netdevice->stats.tx_packets++; |
|
c->netdevice->stats.tx_bytes += skb->len; |
|
dev_consume_skb_irq(skb); |
|
} |
|
|
|
/** |
|
* z8530_null_rx - Discard a packet |
|
* @c: The channel the packet arrived on |
|
* @skb: The buffer |
|
* |
|
* We point the receive handler at this function when idle. Instead |
|
* of processing the frames we get to throw them away. |
|
*/ |
|
void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) |
|
{ |
|
dev_kfree_skb_any(skb); |
|
} |
|
EXPORT_SYMBOL(z8530_null_rx); |
|
|
|
/** |
|
* z8530_rx_done - Receive completion callback |
|
* @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 |
|
* |
|
* Called with the lock held |
|
*/ |
|
static void z8530_rx_done(struct z8530_channel *c) |
|
{ |
|
struct sk_buff *skb; |
|
int ct; |
|
|
|
/* Is our receive engine in DMA mode |
|
*/ |
|
if (c->rxdma_on) { |
|
/* Save the ready state and the buffer currently |
|
* being used as the DMA target |
|
*/ |
|
int ready = c->dma_ready; |
|
unsigned char *rxb = c->rx_buf[c->dma_num]; |
|
unsigned long flags; |
|
|
|
/* Complete this DMA. Necessary to find the length |
|
*/ |
|
flags = claim_dma_lock(); |
|
|
|
disable_dma(c->rxdma); |
|
clear_dma_ff(c->rxdma); |
|
c->rxdma_on = 0; |
|
ct = c->mtu - get_dma_residue(c->rxdma); |
|
if (ct < 0) |
|
ct = 2; /* Shit happens.. */ |
|
c->dma_ready = 0; |
|
|
|
/* Normal case: the other slot is free, start the next DMA |
|
* into it immediately. |
|
*/ |
|
|
|
if (ready) { |
|
c->dma_num ^= 1; |
|
set_dma_mode(c->rxdma, DMA_MODE_READ | 0x10); |
|
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num])); |
|
set_dma_count(c->rxdma, c->mtu); |
|
c->rxdma_on = 1; |
|
enable_dma(c->rxdma); |
|
/* Stop any frames that we missed the head of |
|
* from passing |
|
*/ |
|
write_zsreg(c, R0, RES_Rx_CRC); |
|
} else { |
|
/* Can't occur as we dont reenable the DMA irq until |
|
* after the flip is done |
|
*/ |
|
netdev_warn(c->netdevice, "DMA flip overrun!\n"); |
|
} |
|
|
|
release_dma_lock(flags); |
|
|
|
/* Shove the old buffer into an sk_buff. We can't DMA |
|
* directly into one on a PC - it might be above the 16Mb |
|
* boundary. Optimisation - we could check to see if we |
|
* can avoid the copy. Optimisation 2 - make the memcpy |
|
* a copychecksum. |
|
*/ |
|
|
|
skb = dev_alloc_skb(ct); |
|
if (!skb) { |
|
c->netdevice->stats.rx_dropped++; |
|
netdev_warn(c->netdevice, "Memory squeeze\n"); |
|
} else { |
|
skb_put(skb, ct); |
|
skb_copy_to_linear_data(skb, rxb, ct); |
|
c->netdevice->stats.rx_packets++; |
|
c->netdevice->stats.rx_bytes += ct; |
|
} |
|
c->dma_ready = 1; |
|
} else { |
|
RT_LOCK; |
|
skb = c->skb; |
|
|
|
/* The game we play for non DMA is similar. We want to |
|
* get the controller set up for the next packet as fast |
|
* as possible. We potentially only have one byte + the |
|
* fifo length for this. Thus we want to flip to the new |
|
* buffer and then mess around copying and allocating |
|
* things. For the current case it doesn't matter but |
|
* if you build a system where the sync irq isn't blocked |
|
* by the kernel IRQ disable then you need only block the |
|
* sync IRQ for the RT_LOCK area. |
|
* |
|
*/ |
|
ct = c->count; |
|
|
|
c->skb = c->skb2; |
|
c->count = 0; |
|
c->max = c->mtu; |
|
if (c->skb) { |
|
c->dptr = c->skb->data; |
|
c->max = c->mtu; |
|
} else { |
|
c->count = 0; |
|
c->max = 0; |
|
} |
|
RT_UNLOCK; |
|
|
|
c->skb2 = dev_alloc_skb(c->mtu); |
|
if (c->skb2) |
|
skb_put(c->skb2, c->mtu); |
|
|
|
c->netdevice->stats.rx_packets++; |
|
c->netdevice->stats.rx_bytes += ct; |
|
} |
|
/* If we received a frame we must now process it. |
|
*/ |
|
if (skb) { |
|
skb_trim(skb, ct); |
|
c->rx_function(c, skb); |
|
} else { |
|
c->netdevice->stats.rx_dropped++; |
|
netdev_err(c->netdevice, "Lost a frame\n"); |
|
} |
|
} |
|
|
|
/** |
|
* spans_boundary - Check a packet can be ISA DMA'd |
|
* @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. |
|
*/ |
|
|
|
static inline int spans_boundary(struct sk_buff *skb) |
|
{ |
|
unsigned long a = (unsigned long)skb->data; |
|
|
|
a ^= (a + skb->len); |
|
if (a & 0x00010000) /* If the 64K bit is different.. */ |
|
return 1; |
|
return 0; |
|
} |
|
|
|
/** |
|
* z8530_queue_xmit - Queue a packet |
|
* @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 |
|
* not in the IRQ. |
|
* |
|
* Called from the network code. The lock is not held at this |
|
* point. |
|
*/ |
|
netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) |
|
{ |
|
unsigned long flags; |
|
|
|
netif_stop_queue(c->netdevice); |
|
if (c->tx_next_skb) |
|
return NETDEV_TX_BUSY; |
|
|
|
/* PC SPECIFIC - DMA limits */ |
|
/* If we will DMA the transmit and its gone over the ISA bus |
|
* limit, then copy to the flip buffer |
|
*/ |
|
|
|
if (c->dma_tx && |
|
((unsigned long)(virt_to_bus(skb->data + skb->len)) >= |
|
16 * 1024 * 1024 || spans_boundary(skb))) { |
|
/* Send the flip buffer, and flip the flippy bit. |
|
* We don't care which is used when just so long as |
|
* we never use the same buffer twice in a row. Since |
|
* only one buffer can be going out at a time the other |
|
* has to be safe. |
|
*/ |
|
c->tx_next_ptr = c->tx_dma_buf[c->tx_dma_used]; |
|
c->tx_dma_used ^= 1; /* Flip temp buffer */ |
|
skb_copy_from_linear_data(skb, c->tx_next_ptr, skb->len); |
|
} else { |
|
c->tx_next_ptr = skb->data; |
|
} |
|
RT_LOCK; |
|
c->tx_next_skb = skb; |
|
RT_UNLOCK; |
|
|
|
spin_lock_irqsave(c->lock, flags); |
|
z8530_tx_begin(c); |
|
spin_unlock_irqrestore(c->lock, flags); |
|
|
|
return NETDEV_TX_OK; |
|
} |
|
EXPORT_SYMBOL(z8530_queue_xmit); |
|
|
|
/* Module support |
|
*/ |
|
static const char banner[] __initconst = |
|
KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"; |
|
|
|
static int __init z85230_init_driver(void) |
|
{ |
|
printk(banner); |
|
return 0; |
|
} |
|
module_init(z85230_init_driver); |
|
|
|
static void __exit z85230_cleanup_driver(void) |
|
{ |
|
} |
|
module_exit(z85230_cleanup_driver); |
|
|
|
MODULE_AUTHOR("Red Hat Inc."); |
|
MODULE_DESCRIPTION("Z85x30 synchronous driver core"); |
|
MODULE_LICENSE("GPL");
|
|
|