patch-2.3.18 linux/drivers/atm/horizon.c
Next file: linux/drivers/atm/horizon.h
Previous file: linux/drivers/atm/eni.c
Back to the patch index
Back to the overall index
- Lines: 598
- Date:
Wed Sep 8 11:14:31 1999
- Orig file:
v2.3.17/linux/drivers/atm/horizon.c
- Orig date:
Tue Aug 31 17:29:13 1999
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c
@@ -50,9 +50,9 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Horizon [Ultra] driver"
-#define version_string "1.1"
+#define version_string "1.2"
-static void __init show_version (void) {
+static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
}
@@ -86,7 +86,7 @@
The driver is only known to work with SONET and UTP Horizon Ultra
cards at 155Mb/s. However, code is in place to deal with both the
- original Horizon and 35Mb/s.
+ original Horizon and 25Mb/s operation.
There are two revisions of the Horizon ASIC: the original and the
Ultra. Details of hardware bugs are in section III.
@@ -127,15 +127,15 @@
3. Initialisation
- The card is reset and then put into a know state. The physical layer
- is configured for normal operation at the appropriate speed; in the
- case of the 155 cards, the framer is initialised with line-based
- timing; the internal RAM is zeroed and the allocation of buffers for
- RX and TX is made; the Burnt In Address is read and copied to the
- ATM ESI; various policy settings for RX (VPI bits, unknown VCs, oam
- cells) are made. Ideally all policy items should be configurable at
- module load (if not actually on-demand), however, only the vpi vs
- vci bit allocation can be specified at insmod.
+ The card is reset and then put into a known state. The physical
+ layer is configured for normal operation at the appropriate speed;
+ in the case of the 155 cards, the framer is initialised with
+ line-based timing; the internal RAM is zeroed and the allocation of
+ buffers for RX and TX is made; the Burnt In Address is read and
+ copied to the ATM ESI; various policy settings for RX (VPI bits,
+ unknown VCs, oam cells) are made. Ideally all policy items should be
+ configurable at module load (if not actually on-demand), however,
+ only the vpi vs vci bit allocation can be specified at insmod.
4. Shutdown
@@ -152,12 +152,12 @@
the following items they make up the traffic specification.
struct atm_trafprm {
- unsigned char traffic_class; traffic class (ATM_UBR, ...)
- int max_pcr; maximum PCR in cells per second
- int pcr; desired PCR in cells per second
- int min_pcr; minimum PCR in cells per second
- int max_cdv; maximum CDV in microseconds
- int max_sdu; maximum SDU in bytes
+ unsigned char traffic_class; traffic class (ATM_UBR, ...)
+ int max_pcr; maximum PCR in cells per second
+ int pcr; desired PCR in cells per second
+ int min_pcr; minimum PCR in cells per second
+ int max_cdv; maximum CDV in microseconds
+ int max_sdu; maximum SDU in bytes
};
Note that these denote bandwidth available not bandwidth used; the
@@ -206,30 +206,31 @@
AAL types are:
- ATM_NO_AAL AAL not specified
- ATM_AAL0 "raw" ATM cells
- ATM_AAL1 AAL1 (CBR)
- ATM_AAL2 AAL2 (VBR)
- ATM_AAL34 AAL3/4 (data)
- ATM_AAL5 AAL5 (data)
- ATM_SAAL signaling AAL
+ ATM_NO_AAL AAL not specified
+ ATM_AAL0 "raw" ATM cells
+ ATM_AAL1 AAL1 (CBR)
+ ATM_AAL2 AAL2 (VBR)
+ ATM_AAL34 AAL3/4 (data)
+ ATM_AAL5 AAL5 (data)
+ ATM_SAAL signaling AAL
The Horizon has support for AAL frame types: 0, 3/4 and 5. However,
it does not implement AAL 3/4 SAR and it has a different notion of
"raw cell" to ATM Linux's (48 bytes vs. 52 bytes) so neither are
supported by this driver.
- The Horizon has (TX) support for ABR (including UBR), VBR and CBR.
- Each TX channel has a bucket (containing up to 31 cell units) and
- two timers (PCR and SCR) associated with it that can be used to
- govern cell emissions and host notification (in the case of
- ABR). The timers may either be disabled or may be set to any of 240
- values (determined by the clock crystal, a fixed (?) per-device
- divider, a configurable divider and a configurable timer preload
- value).
-
- At the moment only UBR and CBR are supported by the driver. This is
- due to my not understanding ATM Linux VBR or Horizon's VBR support.
+ The Horizon has limited support for ABR (including UBR), VBR and
+ CBR. Each TX channel has a bucket (containing up to 31 cell units)
+ and two timers (PCR and SCR) associated with it that can be used to
+ govern cell emissions and host notification (in the case of ABR this
+ is presumably so that RM cells may be emitted at appropriate times).
+ The timers may either be disabled or may be set to any of 240 values
+ (determined by the clock crystal, a fixed (?) per-device divider, a
+ configurable divider and a configurable timer preload value).
+
+ At the moment only UBR and CBR are supported by the driver. VBR will
+ be supported as soon as ATM for Linux supports it. ABR support is
+ very unlikely as RM cell handling is completely up to the driver.
1. TX (TX channel setup and TX transfer)
@@ -305,7 +306,7 @@
in the TX direction on the original Horizon. More complicated
solutions are likely to hurt my brain.
- 3. Loss of buffer on close VC
+ 2. Loss of buffer on close VC
When a VC is being closed, the buffer associated with it is not
returned to the pool. The host must store the reference to this
@@ -314,7 +315,7 @@
The host intervention currently consists of stacking such a buffer
pointer at VC close and checking the stack at VC open.
- 4. Failure to close a VC
+ 3. Failure to close a VC
If a VC is currently receiving a frame then closing the VC may fail
and the frame continues to be received.
@@ -322,7 +323,7 @@
The solution is to make sure any received frames are flushed when
ready. This is currently done just before the solution to 3.
- 5. PCI bus (original Horizon only, fixed in Ultra)
+ 4. PCI bus (original Horizon only, fixed in Ultra)
Reading from the data port prior to initialisation will hang the PCI
bus. Just don't do that then! We don't.
@@ -388,10 +389,9 @@
insb (dev->iobase + reg, addr, len);
}
-/* Read / Write to a given address in Horizon buffer memory. */
-// Interrupts must be disabled between the address register and data port
-// accesses as these must form an atomic operation.
-
+/* Read / Write to a given address in Horizon buffer memory.
+ Interrupts must be disabled between the address register and data
+ port accesses as these must form an atomic operation. */
static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) {
// wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr);
wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW));
@@ -401,7 +401,7 @@
static inline u32 rd_mem (const hrz_dev * dev, HDW * addr) {
// wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr);
wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW));
- return rd_regl(dev, MEMORY_PORT_OFF);
+ return rd_regl (dev, MEMORY_PORT_OFF);
}
static inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) {
@@ -511,7 +511,7 @@
/* RX channels are 10 bit integers, these fns are quite paranoid */
-static inline int channel_to_vpci (const u16 channel, short * vpi, int * vci) {
+static inline int channel_to_vpivci (const u16 channel, short * vpi, int * vci) {
unsigned short vci_bits = 10 - vpi_bits;
if ((channel & RX_CHANNEL_MASK) == channel) {
*vci = channel & ((~0)<<vci_bits);
@@ -521,7 +521,7 @@
return -EINVAL;
}
-static inline int vpci_to_channel (u16 * channel, const short vpi, const int vci) {
+static inline int vpivci_to_channel (u16 * channel, const short vpi, const int vci) {
unsigned short vci_bits = 10 - vpi_bits;
if (0 <= vpi && vpi < 1<<vpi_bits && 0 <= vci && vci < 1<<vci_bits) {
*channel = vpi<<vci_bits | vci;
@@ -746,7 +746,7 @@
static int hrz_open_rx (hrz_dev * dev, u16 channel) {
// is there any guarantee that we don't get two simulataneous
// identical calls of this function from different processes? yes
- // rates_lock
+ // rate_lock
unsigned long flags;
u32 channel_type; // u16?
@@ -786,13 +786,13 @@
spin_lock_irqsave (&dev->mem_lock, flags);
wr_mem (dev, &rx_desc->wr_buf_type,
- buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME);
+ buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME);
if (buf_ptr != RX_CHANNEL_IDLE)
wr_mem (dev, &rx_desc->rd_buf_type, buf_ptr);
spin_unlock_irqrestore (&dev->mem_lock, flags);
- // rxer->rate = make_rate (qos->peak_cells);
+ // rxer->rate = make_rate (qos->peak_cells);
PRINTD (DBG_FLOW, "hrz_open_rx ok");
@@ -1340,12 +1340,12 @@
if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) {
if (rx_len <= atm_vcc->qos.rxtp.max_sdu) {
-
+ struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC);
+
// If everyone has to call atm_pdu2... why isn't it part of
// atm_charge? B'cos some people already have skb->truesize!
- if (atm_charge (atm_vcc, atm_pdu2truesize (rx_len))) {
-
- struct sk_buff * skb = alloc_skb (rx_len, GFP_ATOMIC);
+ // WA: well. even if they think they do, they might not ... :-)
+
if (skb) {
// remember this so we can push it later
dev->rx_skb = skb;
@@ -1369,15 +1369,8 @@
return;
} else {
- PRINTD (DBG_SKB|DBG_WARN, "failed to get skb");
- atm_vcc->stats->rx_drop++;
+ PRINTD (DBG_INFO, "failed to get skb");
}
-
- } else {
- // someone fix this (message), please!
- PRINTD (DBG_INFO, "dropped thanks to atm_charge");
- // drop stats incremented in atm_charge
- }
} else {
PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel);
@@ -1385,7 +1378,7 @@
}
} else {
- PRINTK (KERN_WARNING, "dropped over-size frame");
+ PRINTK (KERN_WARNING, "dropped over-size frame");
// do we count this?
}
@@ -1573,7 +1566,7 @@
vcc->tx_pcr_bits);
#if 0
- if (a vbr channel) {
+ if (vcc->tx_xbr_bits == VBR_RATE_TYPE) {
// SCR timer
update_tx_channel_config (dev, tx_channel, SCR_TIMER_ACCESS,
vcc->tx_scr_bits);
@@ -1584,9 +1577,9 @@
// ... and fullness
update_tx_channel_config (dev, tx_channel, BUCKET_FULLNESS_ACCESS,
- vcc->tx_bucket_bits);
+ vcc->tx_bucket_bits);
}
-#endif
+#endif
// Initialise the read and write buffer pointers
rd_ptr = rd_mem (dev, &tx_desc->rd_buf_type) & BUFFER_PTR_MASK;
@@ -1723,7 +1716,7 @@
free_buffers, buffers_required);
// what is the appropriate delay? implement a timeout? (depending on line speed?)
// mdelay (1);
- // what happens if kill (current_pid, SIGKILL) ?
+ // what happens if we kill (current_pid, SIGKILL) ?
schedule();
if (++spin_count > 1000) {
PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d",
@@ -1743,7 +1736,7 @@
for (tx_channel = 0; tx_channel < TX_CHANS; ++tx_channel)
if (dev->tx_channel_record[tx_channel] == channel) {
PRINTD (DBG_TX, "vc already on channel: hit");
- break;
+ break;
}
if (tx_channel == TX_CHANS) {
PRINTD (DBG_TX, "vc already on channel: miss");
@@ -1802,7 +1795,7 @@
/********** reset a card **********/
-static void __init hrz_reset_card (const hrz_dev * dev) {
+static void __init hrz_reset (const hrz_dev * dev) {
u32 control_0_reg = rd_regl (dev, CONTROL_0_REG);
// why not set RESET_HORIZON to one and wait for the card to
@@ -1813,7 +1806,7 @@
control_0_reg = rd_regl (dev, CONTROL_0_REG);
// old reset code retained:
- wr_regl (dev, CONTROL_0_REG, control_0_reg |
+ wr_regl (dev, CONTROL_0_REG, control_0_reg |
RESET_ATM | RESET_RX | RESET_TX | RESET_HOST);
// just guessing here
udelay (1000);
@@ -1821,18 +1814,6 @@
wr_regl (dev, CONTROL_0_REG, control_0_reg);
}
-/********** shutdown a card **********/
-
-#ifdef MODULE
-
-static void hrz_shutdown (const hrz_dev * dev) {
- hrz_reset_card (dev);
-
- GREEN_LED_OFF(dev);
-}
-
-#endif
-
/********** read the burnt in address **********/
static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
@@ -1931,7 +1912,7 @@
// Reset the card to get everything in a known state
printk (" reset");
- hrz_reset_card (dev);
+ hrz_reset (dev);
// Clear all the buffer memory
@@ -2105,9 +2086,9 @@
for (i=0; i < ESI_LEN; ++i) {
if (i % 2 == 0)
- b = read_bia (dev, i/2 + 2);
+ b = read_bia (dev, i/2 + 2);
else
- b = b >> 8;
+ b = b >> 8;
esi[i] = b & 0xFF;
printk ("%02x", esi[i]);
}
@@ -2199,8 +2180,8 @@
hrz_vcc * vccp; // allocated late
PRINTD (DBG_FLOW|DBG_VCC, "hrz_open %x %x", vpi, vci);
+#ifdef ATM_VPI_UNSPEC
// UNSPEC is deprecated, remove this code eventually
-#if defined ATM_VPI_UNSPEC
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) {
PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)");
return -EINVAL;
@@ -2215,7 +2196,7 @@
}
PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci);
- error = vpci_to_channel (&channel, vpi, vci);
+ error = vpivci_to_channel (&channel, vpi, vci);
if (error) {
PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci);
return error;
@@ -2459,7 +2440,7 @@
// slight race (no locking) here so we may get -EAGAIN
// later; the greedy bastards would deserve it :)
PRINTD (DBG_QOS, "snatching all remaining RX bandwidth");
- pcr = dev->tx_avail;
+ pcr = dev->rx_avail;
} else if (pcr < 0) {
pcr = -pcr;
}
@@ -2472,14 +2453,15 @@
}
break;
}
+#if 0
case ATM_VBR: {
- // int scr = atm_scr_goal (txtp);
+ // int scr = atm_scr_goal (rxtp);
int scr = 1<<16; // just for fun
if (!scr) {
// slight race (no locking) here so we may get -EAGAIN
// later; the greedy bastards would deserve it :)
PRINTD (DBG_QOS, "snatching all remaining RX bandwidth");
- scr = dev->tx_avail;
+ scr = dev->rx_avail;
} else if (scr < 0) {
scr = -scr;
}
@@ -2492,6 +2474,7 @@
}
break;
}
+#endif
default: {
PRINTD (DBG_QOS, "unsupported RX traffic class");
return -EINVAL;
@@ -2632,8 +2615,10 @@
MOD_DEC_USE_COUNT;
}
+#if 0
static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname,
void *optval, int optlen) {
+ hrz_dev * dev = HRZ_DEV(atm_vcc->dev);
PRINTD (DBG_FLOW|DBG_VCC, "hrz_getsockopt");
switch (level) {
case SOL_SOCKET:
@@ -2655,6 +2640,7 @@
static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname,
void *optval, int optlen) {
+ hrz_dev * dev = HRZ_DEV(atm_vcc->dev);
PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt");
switch (level) {
case SOL_SOCKET:
@@ -2673,6 +2659,7 @@
}
return -EINVAL;
}
+#endif
static int hrz_sg_send (struct atm_vcc * atm_vcc,
unsigned long start,
@@ -2722,15 +2709,15 @@
/* more diagnostics here? */
#if 0
- {
- // VBR temporary diags
+ if (!left--) {
+ unsigned int count = sprintf (page, "vbr buckets:");
unsigned int i;
- for (i = 0; i < TX_CHANS; ++i) {
- if (!left--)
- return sprintf (page, "bucket %u: %u/%u\n", i,
+ for (i = 0; i < TX_CHANS; ++i)
+ count += sprintf (page, " %u/%u",
query_tx_channel_config (dev, i, BUCKET_FULLNESS_ACCESS),
query_tx_channel_config (dev, i, BUCKET_CAPACITY_ACCESS));
- }
+ count += sprintf (page+count, ".\n");
+ return count;
}
#endif
@@ -2760,8 +2747,8 @@
hrz_open,
hrz_close,
NULL, // no hrz_ioctl
- hrz_getsockopt,
- hrz_setsockopt,
+ NULL, // hrz_getsockopt,
+ NULL, // hrz_setsockopt,
hrz_send,
hrz_sg_send,
NULL, // no send_oam - not in fact used yet
@@ -2811,10 +2798,10 @@
// grab IRQ and install handler - move this someplace more sensible
if (request_irq (irq,
- interrupt_handler,
- SA_SHIRQ, /* irqflags guess */
- DEV_LABEL, /* name guess */
- dev)) {
+ interrupt_handler,
+ SA_SHIRQ, /* irqflags guess */
+ DEV_LABEL, /* name guess */
+ dev)) {
PRINTD (DBG_WARN, "request IRQ failed!");
// free_irq is at "endif"
} else {
@@ -2824,20 +2811,20 @@
dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0);
if (!(dev->atm_dev)) {
- PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
} else {
unsigned char lat;
- PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
+ PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
dev->atm_dev->number, dev, dev->atm_dev);
- dev->atm_dev->dev_data = (void *) dev;
- dev->pci_dev = pci_dev;
-
- /* XXX DEV_LABEL is a guess */
- request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL);
+ dev->atm_dev->dev_data = (void *) dev;
+ dev->pci_dev = pci_dev;
+
+ /* XXX DEV_LABEL is a guess */
+ request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL);
- // enable bus master accesses
- pci_set_master (pci_dev);
+ // enable bus master accesses
+ pci_set_master (pci_dev);
// frobnicate latency (upwards, usually)
pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
@@ -2851,9 +2838,9 @@
pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY);
}
- dev->iobase = iobase;
- dev->irq = irq;
- dev->membase = membase;
+ dev->iobase = iobase;
+ dev->irq = irq;
+ dev->membase = membase;
dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0];
dev->rx_q_wrap = &memmap->rx_q_entries[RX_CHANS-1];
@@ -2882,13 +2869,13 @@
}
dev->flags = 0;
-
+
// Allocate cell rates and remember ASIC version
// Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
// Copper: (WRONG) we want 6 into the above, close to 25Mb/s
// Copper: (plagarise!) 25600000/8/270*260/53 - n/53
- if (hrz_init (dev)) {
+ if (hrz_init (dev)) {
// to be really pedantic, this should be ATM_OC3c_PCR
dev->tx_avail = ATM_OC3_PCR;
dev->rx_avail = ATM_OC3_PCR;
@@ -2906,21 +2893,25 @@
// writes to adapter memory (handles IRQ and SMP)
spin_lock_init (&dev->mem_lock);
- init_waitqueue_head(&dev->tx_queue);
-
- // vpi in 0..4, vci in 6..10
- dev->atm_dev->ci_range.vpi_bits = vpi_bits;
- dev->atm_dev->ci_range.vci_bits = 10-vpi_bits;
-
- // update count and linked list
+#if LINUX_VERSION_CODE >= 0x20303
+ init_waitqueue_head (&dev->tx_queue);
+#else
+ dev->tx_queue = 0;
+#endif
+
+ // vpi in 0..4, vci in 6..10
+ dev->atm_dev->ci_range.vpi_bits = vpi_bits;
+ dev->atm_dev->ci_range.vci_bits = 10-vpi_bits;
+
+ // update count and linked list
++devs;
- dev->prev = hrz_devs;
- hrz_devs = dev;
+ dev->prev = hrz_devs;
+ hrz_devs = dev;
// success
- continue;
-
- /* not currently reached */
- atm_dev_deregister (dev->atm_dev);
+ continue;
+
+ /* not currently reached */
+ atm_dev_deregister (dev->atm_dev);
} /* atm_dev_register */
free_irq (irq, dev);
} /* request_irq */
@@ -2943,11 +2934,11 @@
if (max_tx_size > TX_AAL5_LIMIT)
PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu",
- max_tx_size = TX_AAL5_LIMIT);
+ max_tx_size = TX_AAL5_LIMIT);
if (max_rx_size > RX_AAL5_LIMIT)
PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu",
- max_rx_size = RX_AAL5_LIMIT);
+ max_rx_size = RX_AAL5_LIMIT);
return;
}
@@ -3016,7 +3007,7 @@
hrz_devs = dev->prev;
PRINTD (DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
- hrz_shutdown (dev);
+ hrz_reset (dev);
atm_dev_deregister (dev->atm_dev);
free_irq (dev->irq, dev);
release_region (dev->iobase, HRZ_IO_EXTENT);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)