Release 4.11 drivers/atm/he.c
/*
he.c
ForeRunnerHE ATM Adapter driver for ATM on Linux
Copyright (C) 1999-2001 Naval Research Laboratory
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
he.c
ForeRunnerHE ATM Adapter driver for ATM on Linux
Copyright (C) 1999-2001 Naval Research Laboratory
Permission to use, copy, modify and distribute this software and its
documentation is hereby granted, provided that both the copyright
notice and this permission notice appear in all copies of the software,
derivative works or modified versions, and any portions thereof, and
that both notices appear in supporting documentation.
NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
RESULTING FROM THE USE OF THIS SOFTWARE.
This driver was written using the "Programmer's Reference Manual for
ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98.
AUTHORS:
chas williams <chas@cmf.nrl.navy.mil>
eric kinzie <ekinzie@cmf.nrl.navy.mil>
NOTES:
4096 supported 'connections'
group 0 is used for all traffic
interrupt queue 0 is used for all interrupts
aal0 support (based on work from ulrich.u.muller@nokia.com)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/bitmap.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <linux/uaccess.h>
#include <linux/atmdev.h>
#include <linux/atm.h>
#include <linux/sonet.h>
#undef USE_SCATTERGATHER
#undef USE_CHECKSUM_HW
/* still confused about this */
/* #undef HE_DEBUG */
#include "he.h"
#include "suni.h"
#include <linux/atm_he.h>
#define hprintk(fmt,args...) printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number , ##args)
#ifdef HE_DEBUG
#define HPRINTK(fmt,args...) printk(KERN_DEBUG DEV_LABEL "%d: " fmt, he_dev->number , ##args)
#else /* !HE_DEBUG */
#define HPRINTK(fmt,args...) do { } while (0)
#endif /* HE_DEBUG */
/* declarations */
static int he_open(struct atm_vcc *vcc);
static void he_close(struct atm_vcc *vcc);
static int he_send(struct atm_vcc *vcc, struct sk_buff *skb);
static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);
static irqreturn_t he_irq_handler(int irq, void *dev_id);
static void he_tasklet(unsigned long data);
static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page);
static int he_start(struct atm_dev *dev);
static void he_stop(struct he_dev *dev);
static void he_phy_put(struct atm_dev *, unsigned char, unsigned long);
static unsigned char he_phy_get(struct atm_dev *, unsigned long);
static u8 read_prom_byte(struct he_dev *he_dev, int addr);
/* globals */
static struct he_dev *he_devs;
static bool disable64;
static short nvpibits = -1;
static short nvcibits = -1;
static short rx_skb_reserve = 16;
static bool irq_coalesce = true;
static bool sdh;
/* Read from EEPROM = 0000 0011b */
static unsigned int readtab[] = {
CS_HIGH | CLK_HIGH,
CS_LOW | CLK_LOW,
CLK_HIGH, /* 0 */
CLK_LOW,
CLK_HIGH, /* 0 */
CLK_LOW,
CLK_HIGH, /* 0 */
CLK_LOW,
CLK_HIGH, /* 0 */
CLK_LOW,
CLK_HIGH, /* 0 */
CLK_LOW,
CLK_HIGH, /* 0 */
CLK_LOW | SI_HIGH,
CLK_HIGH | SI_HIGH, /* 1 */
CLK_LOW | SI_HIGH,
CLK_HIGH | SI_HIGH /* 1 */
};
/* Clock to read from/write to the EEPROM */
static unsigned int clocktab[] = {
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW,
CLK_HIGH,
CLK_LOW
};
static struct atmdev_ops he_ops =
{
.open = he_open,
.close = he_close,
.ioctl = he_ioctl,
.send = he_send,
.phy_put = he_phy_put,
.phy_get = he_phy_get,
.proc_read = he_proc_read,
.owner = THIS_MODULE
};
#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while (0)
#define he_readl(dev, reg) readl((dev)->membase + (reg))
/* section 2.12 connection memory access */
static __inline__ void
he_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr,
unsigned flags)
{
he_writel(he_dev, val, CON_DAT);
(void) he_readl(he_dev, CON_DAT); /* flush posted writes */
he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL);
while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 69 | 100.00% | 2 | 100.00% |
Total | 69 | 100.00% | 2 | 100.00% |
#define he_writel_rcm(dev, val, reg) \
he_writel_internal(dev, val, reg, CON_CTL_RCM)
#define he_writel_tcm(dev, val, reg) \
he_writel_internal(dev, val, reg, CON_CTL_TCM)
#define he_writel_mbox(dev, val, reg) \
he_writel_internal(dev, val, reg, CON_CTL_MBOX)
static unsigned
he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags)
{
he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL);
while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
return he_readl(he_dev, CON_DAT);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 53 | 100.00% | 1 | 100.00% |
Total | 53 | 100.00% | 1 | 100.00% |
#define he_readl_rcm(dev, reg) \
he_readl_internal(dev, reg, CON_CTL_RCM)
#define he_readl_tcm(dev, reg) \
he_readl_internal(dev, reg, CON_CTL_TCM)
#define he_readl_mbox(dev, reg) \
he_readl_internal(dev, reg, CON_CTL_MBOX)
/* figure 2.2 connection id */
#define he_mkcid(dev, vpi, vci) (((vpi << (dev)->vcibits) | vci) & 0x1fff)
/* 2.5.1 per connection transmit state registers */
#define he_writel_tsr0(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 0)
#define he_readl_tsr0(dev, cid) \
he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 0)
#define he_writel_tsr1(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 1)
#define he_writel_tsr2(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 2)
#define he_writel_tsr3(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 3)
#define he_writel_tsr4(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 4)
/* from page 2-20
*
* NOTE While the transmit connection is active, bits 23 through 0
* of this register must not be written by the host. Byte
* enables should be used during normal operation when writing
* the most significant byte.
*/
#define he_writel_tsr4_upper(dev, val, cid) \
he_writel_internal(dev, val, CONFIG_TSRA | (cid << 3) | 4, \
CON_CTL_TCM \
| CON_BYTE_DISABLE_2 \
| CON_BYTE_DISABLE_1 \
| CON_BYTE_DISABLE_0)
#define he_readl_tsr4(dev, cid) \
he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 4)
#define he_writel_tsr5(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 5)
#define he_writel_tsr6(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 6)
#define he_writel_tsr7(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 7)
#define he_writel_tsr8(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 0)
#define he_writel_tsr9(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 1)
#define he_writel_tsr10(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 2)
#define he_writel_tsr11(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 3)
#define he_writel_tsr12(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 0)
#define he_writel_tsr13(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 1)
#define he_writel_tsr14(dev, val, cid) \
he_writel_tcm(dev, val, CONFIG_TSRD | cid)
#define he_writel_tsr14_upper(dev, val, cid) \
he_writel_internal(dev, val, CONFIG_TSRD | cid, \
CON_CTL_TCM \
| CON_BYTE_DISABLE_2 \
| CON_BYTE_DISABLE_1 \
| CON_BYTE_DISABLE_0)
/* 2.7.1 per connection receive state registers */
#define he_writel_rsr0(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 0)
#define he_readl_rsr0(dev, cid) \
he_readl_rcm(dev, 0x00000 | (cid << 3) | 0)
#define he_writel_rsr1(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 1)
#define he_writel_rsr2(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 2)
#define he_writel_rsr3(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 3)
#define he_writel_rsr4(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 4)
#define he_writel_rsr5(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 5)
#define he_writel_rsr6(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 6)
#define he_writel_rsr7(dev, val, cid) \
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7)
static __inline__ struct atm_vcc*
__find_vcc(struct he_dev *he_dev, unsigned cid)
{
struct hlist_head *head;
struct atm_vcc *vcc;
struct sock *s;
short vpi;
int vci;
vpi = cid >> he_dev->vcibits;
vci = cid & ((1 << he_dev->vcibits) - 1);
head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)];
sk_for_each(s, head) {
vcc = atm_sk(s);
if (vcc->dev == he_dev->atm_dev &&
vcc->vci == vci && vcc->vpi == vpi &&
vcc->qos.rxtp.traffic_class != ATM_NONE) {
return vcc;
}
}
return NULL;
}
static
int he_init_one(struct pci_dev *pci_dev,
const struct pci_device_id *pci_ent)
{
struct atm_dev *atm_dev = NULL;
struct he_dev *he_dev = NULL;
int err = 0;
printk(KERN_INFO "ATM he driver\n");
if (pci_enable_device(pci_dev))
return -EIO;
if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)) != 0) {
printk(KERN_WARNING "he: no suitable dma available\n");
err = -EIO;
goto init_one_failure;
}
atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL);
if (!atm_dev) {
err = -ENODEV;
goto init_one_failure;
}
pci_set_drvdata(pci_dev, atm_dev);
he_dev = kzalloc(sizeof(struct he_dev),
GFP_KERNEL);
if (!he_dev) {
err = -ENOMEM;
goto init_one_failure;
}
he_dev->pci_dev = pci_dev;
he_dev->atm_dev = atm_dev;
he_dev->atm_dev->dev_data = he_dev;
atm_dev->dev_data = he_dev;
he_dev->number = atm_dev->number;
tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev);
spin_lock_init(&he_dev->global_lock);
if (he_start(atm_dev)) {
he_stop(he_dev);
err = -ENODEV;
goto init_one_failure;
}
he_dev->next = NULL;
if (he_devs)
he_dev->next = he_devs;
he_devs = he_dev;
return 0;
init_one_failure:
if (atm_dev)
atm_dev_deregister(atm_dev);
kfree(he_dev);
pci_disable_device(pci_dev);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 268 | 94.70% | 4 | 36.36% |
Dan J Williams | 5 | 1.77% | 1 | 9.09% |
Yang Hongyang | 4 | 1.41% | 1 | 9.09% |
Andrew Morton | 2 | 0.71% | 1 | 9.09% |
Om Narasimhan | 1 | 0.35% | 1 | 9.09% |
Al Viro | 1 | 0.35% | 1 | 9.09% |
Greg Kroah-Hartman | 1 | 0.35% | 1 | 9.09% |
Adrian Bunk | 1 | 0.35% | 1 | 9.09% |
Total | 283 | 100.00% | 11 | 100.00% |
static void he_remove_one(struct pci_dev *pci_dev)
{
struct atm_dev *atm_dev;
struct he_dev *he_dev;
atm_dev = pci_get_drvdata(pci_dev);
he_dev = HE_DEV(atm_dev);
/* need to remove from he_devs */
he_stop(he_dev);
atm_dev_deregister(atm_dev);
kfree(he_dev);
pci_disable_device(pci_dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 56 | 100.00% | 2 | 100.00% |
Total | 56 | 100.00% | 2 | 100.00% |
static unsigned
rate_to_atmf(unsigned rate) /* cps to atm forum format */
{
#define NONZERO (1 << 14)
unsigned exp = 0;
if (rate == 0)
return 0;
rate <<= 9;
while (rate > 0x3ff) {
++exp;
rate >>= 1;
}
return (NONZERO | (exp << 9) | (rate & 0x1ff));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 64 | 100.00% | 2 | 100.00% |
Total | 64 | 100.00% | 2 | 100.00% |
static void he_init_rx_lbfp0(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row;
lbufd_index = 0;
lbm_offset = he_readl(he_dev, RCMLBM_BA);
he_writel(he_dev, lbufd_index, RLBF0_H);
for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) {
lbufd_index += 2;
lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
if (++lbuf_count == lbufs_per_row) {
lbuf_count = 0;
row_offset += he_dev->bytes_per_row;
}
lbm_offset += 4;
}
he_writel(he_dev, lbufd_index - 2, RLBF0_T);
he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 179 | 100.00% | 1 | 100.00% |
Total | 179 | 100.00% | 1 | 100.00% |
static void he_init_rx_lbfp1(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row;
lbufd_index = 1;
lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index);
he_writel(he_dev, lbufd_index, RLBF1_H);
for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) {
lbufd_index += 2;
lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
if (++lbuf_count == lbufs_per_row) {
lbuf_count = 0;
row_offset += he_dev->bytes_per_row;
}
lbm_offset += 4;
}
he_writel(he_dev, lbufd_index - 2, RLBF1_T);
he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 185 | 100.00% | 1 | 100.00% |
Total | 185 | 100.00% | 1 | 100.00% |
static void he_init_tx_lbfp(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row;
lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs;
lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index);
he_writel(he_dev, lbufd_index, TLBF_H);
for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) {
lbufd_index += 1;
lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
if (++lbuf_count == lbufs_per_row) {
lbuf_count = 0;
row_offset += he_dev->bytes_per_row;
}
lbm_offset += 2;
}
he_writel(he_dev, lbufd_index - 1, TLBF_T);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 180 | 100.00% | 1 | 100.00% |
Total | 180 | 100.00% | 1 | 100.00% |
static int he_init_tpdrq(struct he_dev *he_dev)
{
he_dev->tpdrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev,
CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq),
&he_dev->tpdrq_phys, GFP_KERNEL);
if (he_dev->tpdrq_base == NULL) {
hprintk("failed to alloc tpdrq\n");
return -ENOMEM;
}
he_dev->tpdrq_tail = he_dev->tpdrq_base;
he_dev->tpdrq_head = he_dev->tpdrq_base;
he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H);
he_writel(he_dev, 0, TPDRQ_T);
he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 109 | 100.00% | 3 | 100.00% |
Total | 109 | 100.00% | 3 | 100.00% |
static void he_init_cs_block(struct he_dev *he_dev)
{
unsigned clock, rate, delta;
int reg;
/* 5.1.7 cs block initialization */
for (reg = 0; reg < 0x20; ++reg)
he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg);
/* rate grid timer reload values */
clock = he_is622(he_dev) ? 66667000 : 50000000;
rate = he_dev->atm_dev->link_rate;
delta = rate / 16 / 2;
for (reg = 0; reg < 0x10; ++reg) {
/* 2.4 internal transmit function
*
* we initialize the first row in the rate grid.
* values are period (in clock cycles) of timer
*/
unsigned period = clock / rate;
he_writel_mbox(he_dev, period, CS_TGRLD0 + reg);
rate -= delta;
}
if (he_is622(he_dev)) {
/* table 5.2 (4 cells per lbuf) */
he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0);
he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1);
he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2);
he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3);
he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4);
/* table 5.3, 5.4, 5.5, 5.6, 5.7 */
he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0);
he_writel_mbox(he_dev, 0x1801, CS_ERCTL1);
he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2);
he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0);
he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1);
he_writel_mbox(he_dev, 0x14585, CS_RTFWR);
he_writel_mbox(he_dev, 0x4680, CS_RTATR);
/* table 5.8 */
he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET);
he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX);
he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN);
he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC);
he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC);
he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL);
/* table 5.9 */
he_writel_mbox(he_dev, 0x5, CS_OTPPER);
he_writel_mbox(he_dev, 0x14, CS_OTWPER);
} else {
/* table 5.1 (4 cells per lbuf) */
he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0);
he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1);
he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2);
he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3);
he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4);
/* table 5.3, 5.4, 5.5, 5.6, 5.7 */
he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0);
he_writel_mbox(he_dev, 0x4701, CS_ERCTL1);
he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2);
he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0);
he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1);
he_writel_mbox(he_dev, 0xf424, CS_RTFWR);
he_writel_mbox(he_dev, 0x4680, CS_RTATR);
/* table 5.8 */
he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET);
he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX);
he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN);
he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC);
he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC);
he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL);
/* table 5.9 */
he_writel_mbox(he_dev, 0x6, CS_OTPPER);
he_writel_mbox(he_dev, 0x1e, CS_OTWPER);
}
he_writel_mbox(he_dev, 0x8, CS_OTTLIM);
for (reg = 0; reg < 0x8; ++reg)
he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 525 | 100.00% | 1 | 100.00% |
Total | 525 | 100.00% | 1 | 100.00% |
static int he_init_cs_block_rcm(struct he_dev *he_dev)
{
unsigned (*rategrid)[16][16];
unsigned rate, delta;
int i, j, reg;
unsigned rate_atmf, exp, man;
unsigned long long rate_cps;
int mult, buf, buf_limit = 4;
rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL);
if (!rategrid)
return -ENOMEM;
/* initialize rate grid group table */
for (reg = 0x0; reg < 0xff; ++reg)
he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg);
/* initialize rate controller groups */
for (reg = 0x100; reg < 0x1ff; ++reg)
he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg);
/* initialize tNrm lookup table */
/* the manual makes reference to a routine in a sample driver
for proper configuration; fortunately, we only need this
in order to support abr connection */
/* initialize rate to group table */
rate = he_dev->atm_dev->link_rate;
delta = rate / 32;
/*
* 2.4 transmit internal functions
*
* we construct a copy of the rate grid used by the scheduler
* in order to construct the rate to group table below
*/
for (j = 0; j < 16; j++) {
(*rategrid)[0][j] = rate;
rate -= delta;
}
for (i = 1; i < 16; i++)
for (j = 0; j < 16; j++)
if (i > 14)
(*rategrid)[i][j] = (*rategrid)[i - 1][j] / 4;
else
(*rategrid)[i][j] = (*rategrid)[i - 1][j] / 2;
/*
* 2.4 transmit internal function
*
* this table maps the upper 5 bits of exponent and mantissa
* of the atm forum representation of the rate into an index
* on rate grid
*/
rate_atmf = 0;
while (rate_atmf < 0x400) {
man = (rate_atmf & 0x1f) << 4;
exp = rate_atmf >> 5;
/*
instead of '/ 512', use '>> 9' to prevent a call
to divdu3 on x86 platforms
*/
rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9;
if (rate_cps < 10)
rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */
for (i = 255; i > 0; i--)
if ((*rategrid)[i/16][i%