162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci he.c 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci ForeRunnerHE ATM Adapter driver for ATM on Linux 662306a36Sopenharmony_ci Copyright (C) 1999-2001 Naval Research Laboratory 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci This library is free software; you can redistribute it and/or 962306a36Sopenharmony_ci modify it under the terms of the GNU Lesser General Public 1062306a36Sopenharmony_ci License as published by the Free Software Foundation; either 1162306a36Sopenharmony_ci version 2.1 of the License, or (at your option) any later version. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci This library is distributed in the hope that it will be useful, 1462306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 1562306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1662306a36Sopenharmony_ci Lesser General Public License for more details. 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1962306a36Sopenharmony_ci License along with this library; if not, write to the Free Software 2062306a36Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci*/ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci he.c 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci ForeRunnerHE ATM Adapter driver for ATM on Linux 2962306a36Sopenharmony_ci Copyright (C) 1999-2001 Naval Research Laboratory 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci Permission to use, copy, modify and distribute this software and its 3262306a36Sopenharmony_ci documentation is hereby granted, provided that both the copyright 3362306a36Sopenharmony_ci notice and this permission notice appear in all copies of the software, 3462306a36Sopenharmony_ci derivative works or modified versions, and any portions thereof, and 3562306a36Sopenharmony_ci that both notices appear in supporting documentation. 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND 3862306a36Sopenharmony_ci DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 3962306a36Sopenharmony_ci RESULTING FROM THE USE OF THIS SOFTWARE. 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci This driver was written using the "Programmer's Reference Manual for 4262306a36Sopenharmony_ci ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98. 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci AUTHORS: 4562306a36Sopenharmony_ci chas williams <chas@cmf.nrl.navy.mil> 4662306a36Sopenharmony_ci eric kinzie <ekinzie@cmf.nrl.navy.mil> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci NOTES: 4962306a36Sopenharmony_ci 4096 supported 'connections' 5062306a36Sopenharmony_ci group 0 is used for all traffic 5162306a36Sopenharmony_ci interrupt queue 0 is used for all interrupts 5262306a36Sopenharmony_ci aal0 support (based on work from ulrich.u.muller@nokia.com) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <linux/module.h> 5762306a36Sopenharmony_ci#include <linux/kernel.h> 5862306a36Sopenharmony_ci#include <linux/skbuff.h> 5962306a36Sopenharmony_ci#include <linux/pci.h> 6062306a36Sopenharmony_ci#include <linux/errno.h> 6162306a36Sopenharmony_ci#include <linux/types.h> 6262306a36Sopenharmony_ci#include <linux/string.h> 6362306a36Sopenharmony_ci#include <linux/delay.h> 6462306a36Sopenharmony_ci#include <linux/init.h> 6562306a36Sopenharmony_ci#include <linux/mm.h> 6662306a36Sopenharmony_ci#include <linux/sched.h> 6762306a36Sopenharmony_ci#include <linux/timer.h> 6862306a36Sopenharmony_ci#include <linux/interrupt.h> 6962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 7062306a36Sopenharmony_ci#include <linux/bitmap.h> 7162306a36Sopenharmony_ci#include <linux/slab.h> 7262306a36Sopenharmony_ci#include <asm/io.h> 7362306a36Sopenharmony_ci#include <asm/byteorder.h> 7462306a36Sopenharmony_ci#include <linux/uaccess.h> 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#include <linux/atmdev.h> 7762306a36Sopenharmony_ci#include <linux/atm.h> 7862306a36Sopenharmony_ci#include <linux/sonet.h> 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#undef USE_SCATTERGATHER 8162306a36Sopenharmony_ci#undef USE_CHECKSUM_HW /* still confused about this */ 8262306a36Sopenharmony_ci/* #undef HE_DEBUG */ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#include "he.h" 8562306a36Sopenharmony_ci#include "suni.h" 8662306a36Sopenharmony_ci#include <linux/atm_he.h> 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define hprintk(fmt,args...) printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number , ##args) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#ifdef HE_DEBUG 9162306a36Sopenharmony_ci#define HPRINTK(fmt,args...) printk(KERN_DEBUG DEV_LABEL "%d: " fmt, he_dev->number , ##args) 9262306a36Sopenharmony_ci#else /* !HE_DEBUG */ 9362306a36Sopenharmony_ci#define HPRINTK(fmt,args...) do { } while (0) 9462306a36Sopenharmony_ci#endif /* HE_DEBUG */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* declarations */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int he_open(struct atm_vcc *vcc); 9962306a36Sopenharmony_cistatic void he_close(struct atm_vcc *vcc); 10062306a36Sopenharmony_cistatic int he_send(struct atm_vcc *vcc, struct sk_buff *skb); 10162306a36Sopenharmony_cistatic int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); 10262306a36Sopenharmony_cistatic irqreturn_t he_irq_handler(int irq, void *dev_id); 10362306a36Sopenharmony_cistatic void he_tasklet(unsigned long data); 10462306a36Sopenharmony_cistatic int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page); 10562306a36Sopenharmony_cistatic int he_start(struct atm_dev *dev); 10662306a36Sopenharmony_cistatic void he_stop(struct he_dev *dev); 10762306a36Sopenharmony_cistatic void he_phy_put(struct atm_dev *, unsigned char, unsigned long); 10862306a36Sopenharmony_cistatic unsigned char he_phy_get(struct atm_dev *, unsigned long); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic u8 read_prom_byte(struct he_dev *he_dev, int addr); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* globals */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic struct he_dev *he_devs; 11562306a36Sopenharmony_cistatic bool disable64; 11662306a36Sopenharmony_cistatic short nvpibits = -1; 11762306a36Sopenharmony_cistatic short nvcibits = -1; 11862306a36Sopenharmony_cistatic short rx_skb_reserve = 16; 11962306a36Sopenharmony_cistatic bool irq_coalesce = true; 12062306a36Sopenharmony_cistatic bool sdh; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* Read from EEPROM = 0000 0011b */ 12362306a36Sopenharmony_cistatic unsigned int readtab[] = { 12462306a36Sopenharmony_ci CS_HIGH | CLK_HIGH, 12562306a36Sopenharmony_ci CS_LOW | CLK_LOW, 12662306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 12762306a36Sopenharmony_ci CLK_LOW, 12862306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 12962306a36Sopenharmony_ci CLK_LOW, 13062306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 13162306a36Sopenharmony_ci CLK_LOW, 13262306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 13362306a36Sopenharmony_ci CLK_LOW, 13462306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 13562306a36Sopenharmony_ci CLK_LOW, 13662306a36Sopenharmony_ci CLK_HIGH, /* 0 */ 13762306a36Sopenharmony_ci CLK_LOW | SI_HIGH, 13862306a36Sopenharmony_ci CLK_HIGH | SI_HIGH, /* 1 */ 13962306a36Sopenharmony_ci CLK_LOW | SI_HIGH, 14062306a36Sopenharmony_ci CLK_HIGH | SI_HIGH /* 1 */ 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* Clock to read from/write to the EEPROM */ 14462306a36Sopenharmony_cistatic unsigned int clocktab[] = { 14562306a36Sopenharmony_ci CLK_LOW, 14662306a36Sopenharmony_ci CLK_HIGH, 14762306a36Sopenharmony_ci CLK_LOW, 14862306a36Sopenharmony_ci CLK_HIGH, 14962306a36Sopenharmony_ci CLK_LOW, 15062306a36Sopenharmony_ci CLK_HIGH, 15162306a36Sopenharmony_ci CLK_LOW, 15262306a36Sopenharmony_ci CLK_HIGH, 15362306a36Sopenharmony_ci CLK_LOW, 15462306a36Sopenharmony_ci CLK_HIGH, 15562306a36Sopenharmony_ci CLK_LOW, 15662306a36Sopenharmony_ci CLK_HIGH, 15762306a36Sopenharmony_ci CLK_LOW, 15862306a36Sopenharmony_ci CLK_HIGH, 15962306a36Sopenharmony_ci CLK_LOW, 16062306a36Sopenharmony_ci CLK_HIGH, 16162306a36Sopenharmony_ci CLK_LOW 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic const struct atmdev_ops he_ops = 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci .open = he_open, 16762306a36Sopenharmony_ci .close = he_close, 16862306a36Sopenharmony_ci .ioctl = he_ioctl, 16962306a36Sopenharmony_ci .send = he_send, 17062306a36Sopenharmony_ci .phy_put = he_phy_put, 17162306a36Sopenharmony_ci .phy_get = he_phy_get, 17262306a36Sopenharmony_ci .proc_read = he_proc_read, 17362306a36Sopenharmony_ci .owner = THIS_MODULE 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while (0) 17762306a36Sopenharmony_ci#define he_readl(dev, reg) readl((dev)->membase + (reg)) 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* section 2.12 connection memory access */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic __inline__ void 18262306a36Sopenharmony_cihe_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr, 18362306a36Sopenharmony_ci unsigned flags) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci he_writel(he_dev, val, CON_DAT); 18662306a36Sopenharmony_ci (void) he_readl(he_dev, CON_DAT); /* flush posted writes */ 18762306a36Sopenharmony_ci he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL); 18862306a36Sopenharmony_ci while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#define he_writel_rcm(dev, val, reg) \ 19262306a36Sopenharmony_ci he_writel_internal(dev, val, reg, CON_CTL_RCM) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define he_writel_tcm(dev, val, reg) \ 19562306a36Sopenharmony_ci he_writel_internal(dev, val, reg, CON_CTL_TCM) 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#define he_writel_mbox(dev, val, reg) \ 19862306a36Sopenharmony_ci he_writel_internal(dev, val, reg, CON_CTL_MBOX) 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic unsigned 20162306a36Sopenharmony_cihe_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL); 20462306a36Sopenharmony_ci while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); 20562306a36Sopenharmony_ci return he_readl(he_dev, CON_DAT); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define he_readl_rcm(dev, reg) \ 20962306a36Sopenharmony_ci he_readl_internal(dev, reg, CON_CTL_RCM) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci#define he_readl_tcm(dev, reg) \ 21262306a36Sopenharmony_ci he_readl_internal(dev, reg, CON_CTL_TCM) 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci#define he_readl_mbox(dev, reg) \ 21562306a36Sopenharmony_ci he_readl_internal(dev, reg, CON_CTL_MBOX) 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* figure 2.2 connection id */ 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#define he_mkcid(dev, vpi, vci) (((vpi << (dev)->vcibits) | vci) & 0x1fff) 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 2.5.1 per connection transmit state registers */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define he_writel_tsr0(dev, val, cid) \ 22562306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 0) 22662306a36Sopenharmony_ci#define he_readl_tsr0(dev, cid) \ 22762306a36Sopenharmony_ci he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 0) 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define he_writel_tsr1(dev, val, cid) \ 23062306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 1) 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#define he_writel_tsr2(dev, val, cid) \ 23362306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 2) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define he_writel_tsr3(dev, val, cid) \ 23662306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 3) 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#define he_writel_tsr4(dev, val, cid) \ 23962306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 4) 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* from page 2-20 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * NOTE While the transmit connection is active, bits 23 through 0 24462306a36Sopenharmony_ci * of this register must not be written by the host. Byte 24562306a36Sopenharmony_ci * enables should be used during normal operation when writing 24662306a36Sopenharmony_ci * the most significant byte. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci#define he_writel_tsr4_upper(dev, val, cid) \ 25062306a36Sopenharmony_ci he_writel_internal(dev, val, CONFIG_TSRA | (cid << 3) | 4, \ 25162306a36Sopenharmony_ci CON_CTL_TCM \ 25262306a36Sopenharmony_ci | CON_BYTE_DISABLE_2 \ 25362306a36Sopenharmony_ci | CON_BYTE_DISABLE_1 \ 25462306a36Sopenharmony_ci | CON_BYTE_DISABLE_0) 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci#define he_readl_tsr4(dev, cid) \ 25762306a36Sopenharmony_ci he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 4) 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci#define he_writel_tsr5(dev, val, cid) \ 26062306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 5) 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define he_writel_tsr6(dev, val, cid) \ 26362306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 6) 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#define he_writel_tsr7(dev, val, cid) \ 26662306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 7) 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#define he_writel_tsr8(dev, val, cid) \ 27062306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 0) 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci#define he_writel_tsr9(dev, val, cid) \ 27362306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 1) 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci#define he_writel_tsr10(dev, val, cid) \ 27662306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 2) 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci#define he_writel_tsr11(dev, val, cid) \ 27962306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 3) 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#define he_writel_tsr12(dev, val, cid) \ 28362306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 0) 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#define he_writel_tsr13(dev, val, cid) \ 28662306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 1) 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci#define he_writel_tsr14(dev, val, cid) \ 29062306a36Sopenharmony_ci he_writel_tcm(dev, val, CONFIG_TSRD | cid) 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci#define he_writel_tsr14_upper(dev, val, cid) \ 29362306a36Sopenharmony_ci he_writel_internal(dev, val, CONFIG_TSRD | cid, \ 29462306a36Sopenharmony_ci CON_CTL_TCM \ 29562306a36Sopenharmony_ci | CON_BYTE_DISABLE_2 \ 29662306a36Sopenharmony_ci | CON_BYTE_DISABLE_1 \ 29762306a36Sopenharmony_ci | CON_BYTE_DISABLE_0) 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 2.7.1 per connection receive state registers */ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci#define he_writel_rsr0(dev, val, cid) \ 30262306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 0) 30362306a36Sopenharmony_ci#define he_readl_rsr0(dev, cid) \ 30462306a36Sopenharmony_ci he_readl_rcm(dev, 0x00000 | (cid << 3) | 0) 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci#define he_writel_rsr1(dev, val, cid) \ 30762306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 1) 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#define he_writel_rsr2(dev, val, cid) \ 31062306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 2) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci#define he_writel_rsr3(dev, val, cid) \ 31362306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 3) 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#define he_writel_rsr4(dev, val, cid) \ 31662306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 4) 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci#define he_writel_rsr5(dev, val, cid) \ 31962306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 5) 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci#define he_writel_rsr6(dev, val, cid) \ 32262306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 6) 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci#define he_writel_rsr7(dev, val, cid) \ 32562306a36Sopenharmony_ci he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7) 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic __inline__ struct atm_vcc* 32862306a36Sopenharmony_ci__find_vcc(struct he_dev *he_dev, unsigned cid) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct hlist_head *head; 33162306a36Sopenharmony_ci struct atm_vcc *vcc; 33262306a36Sopenharmony_ci struct sock *s; 33362306a36Sopenharmony_ci short vpi; 33462306a36Sopenharmony_ci int vci; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci vpi = cid >> he_dev->vcibits; 33762306a36Sopenharmony_ci vci = cid & ((1 << he_dev->vcibits) - 1); 33862306a36Sopenharmony_ci head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci sk_for_each(s, head) { 34162306a36Sopenharmony_ci vcc = atm_sk(s); 34262306a36Sopenharmony_ci if (vcc->dev == he_dev->atm_dev && 34362306a36Sopenharmony_ci vcc->vci == vci && vcc->vpi == vpi && 34462306a36Sopenharmony_ci vcc->qos.rxtp.traffic_class != ATM_NONE) { 34562306a36Sopenharmony_ci return vcc; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci return NULL; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int he_init_one(struct pci_dev *pci_dev, 35262306a36Sopenharmony_ci const struct pci_device_id *pci_ent) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct atm_dev *atm_dev = NULL; 35562306a36Sopenharmony_ci struct he_dev *he_dev = NULL; 35662306a36Sopenharmony_ci int err = 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci printk(KERN_INFO "ATM he driver\n"); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (pci_enable_device(pci_dev)) 36162306a36Sopenharmony_ci return -EIO; 36262306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)) != 0) { 36362306a36Sopenharmony_ci printk(KERN_WARNING "he: no suitable dma available\n"); 36462306a36Sopenharmony_ci err = -EIO; 36562306a36Sopenharmony_ci goto init_one_failure; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL); 36962306a36Sopenharmony_ci if (!atm_dev) { 37062306a36Sopenharmony_ci err = -ENODEV; 37162306a36Sopenharmony_ci goto init_one_failure; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci pci_set_drvdata(pci_dev, atm_dev); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci he_dev = kzalloc(sizeof(struct he_dev), 37662306a36Sopenharmony_ci GFP_KERNEL); 37762306a36Sopenharmony_ci if (!he_dev) { 37862306a36Sopenharmony_ci err = -ENOMEM; 37962306a36Sopenharmony_ci goto init_one_failure; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci he_dev->pci_dev = pci_dev; 38262306a36Sopenharmony_ci he_dev->atm_dev = atm_dev; 38362306a36Sopenharmony_ci he_dev->atm_dev->dev_data = he_dev; 38462306a36Sopenharmony_ci atm_dev->dev_data = he_dev; 38562306a36Sopenharmony_ci he_dev->number = atm_dev->number; 38662306a36Sopenharmony_ci tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev); 38762306a36Sopenharmony_ci spin_lock_init(&he_dev->global_lock); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (he_start(atm_dev)) { 39062306a36Sopenharmony_ci he_stop(he_dev); 39162306a36Sopenharmony_ci err = -ENODEV; 39262306a36Sopenharmony_ci goto init_one_failure; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci he_dev->next = NULL; 39562306a36Sopenharmony_ci if (he_devs) 39662306a36Sopenharmony_ci he_dev->next = he_devs; 39762306a36Sopenharmony_ci he_devs = he_dev; 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ciinit_one_failure: 40162306a36Sopenharmony_ci if (atm_dev) 40262306a36Sopenharmony_ci atm_dev_deregister(atm_dev); 40362306a36Sopenharmony_ci kfree(he_dev); 40462306a36Sopenharmony_ci pci_disable_device(pci_dev); 40562306a36Sopenharmony_ci return err; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void he_remove_one(struct pci_dev *pci_dev) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct atm_dev *atm_dev; 41162306a36Sopenharmony_ci struct he_dev *he_dev; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci atm_dev = pci_get_drvdata(pci_dev); 41462306a36Sopenharmony_ci he_dev = HE_DEV(atm_dev); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* need to remove from he_devs */ 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci he_stop(he_dev); 41962306a36Sopenharmony_ci atm_dev_deregister(atm_dev); 42062306a36Sopenharmony_ci kfree(he_dev); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci pci_disable_device(pci_dev); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic unsigned 42762306a36Sopenharmony_cirate_to_atmf(unsigned rate) /* cps to atm forum format */ 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci#define NONZERO (1 << 14) 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci unsigned exp = 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (rate == 0) 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rate <<= 9; 43762306a36Sopenharmony_ci while (rate > 0x3ff) { 43862306a36Sopenharmony_ci ++exp; 43962306a36Sopenharmony_ci rate >>= 1; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return (NONZERO | (exp << 9) | (rate & 0x1ff)); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic void he_init_rx_lbfp0(struct he_dev *he_dev) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; 44862306a36Sopenharmony_ci unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; 44962306a36Sopenharmony_ci unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; 45062306a36Sopenharmony_ci unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci lbufd_index = 0; 45362306a36Sopenharmony_ci lbm_offset = he_readl(he_dev, RCMLBM_BA); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci he_writel(he_dev, lbufd_index, RLBF0_H); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) { 45862306a36Sopenharmony_ci lbufd_index += 2; 45962306a36Sopenharmony_ci lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci he_writel_rcm(he_dev, lbuf_addr, lbm_offset); 46262306a36Sopenharmony_ci he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (++lbuf_count == lbufs_per_row) { 46562306a36Sopenharmony_ci lbuf_count = 0; 46662306a36Sopenharmony_ci row_offset += he_dev->bytes_per_row; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci lbm_offset += 4; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci he_writel(he_dev, lbufd_index - 2, RLBF0_T); 47262306a36Sopenharmony_ci he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void he_init_rx_lbfp1(struct he_dev *he_dev) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; 47862306a36Sopenharmony_ci unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; 47962306a36Sopenharmony_ci unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; 48062306a36Sopenharmony_ci unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci lbufd_index = 1; 48362306a36Sopenharmony_ci lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci he_writel(he_dev, lbufd_index, RLBF1_H); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) { 48862306a36Sopenharmony_ci lbufd_index += 2; 48962306a36Sopenharmony_ci lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci he_writel_rcm(he_dev, lbuf_addr, lbm_offset); 49262306a36Sopenharmony_ci he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (++lbuf_count == lbufs_per_row) { 49562306a36Sopenharmony_ci lbuf_count = 0; 49662306a36Sopenharmony_ci row_offset += he_dev->bytes_per_row; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci lbm_offset += 4; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci he_writel(he_dev, lbufd_index - 2, RLBF1_T); 50262306a36Sopenharmony_ci he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic void he_init_tx_lbfp(struct he_dev *he_dev) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; 50862306a36Sopenharmony_ci unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; 50962306a36Sopenharmony_ci unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; 51062306a36Sopenharmony_ci unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs; 51362306a36Sopenharmony_ci lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci he_writel(he_dev, lbufd_index, TLBF_H); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) { 51862306a36Sopenharmony_ci lbufd_index += 1; 51962306a36Sopenharmony_ci lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci he_writel_rcm(he_dev, lbuf_addr, lbm_offset); 52262306a36Sopenharmony_ci he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (++lbuf_count == lbufs_per_row) { 52562306a36Sopenharmony_ci lbuf_count = 0; 52662306a36Sopenharmony_ci row_offset += he_dev->bytes_per_row; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci lbm_offset += 2; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci he_writel(he_dev, lbufd_index - 1, TLBF_T); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int he_init_tpdrq(struct he_dev *he_dev) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci he_dev->tpdrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, 53762306a36Sopenharmony_ci CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), 53862306a36Sopenharmony_ci &he_dev->tpdrq_phys, 53962306a36Sopenharmony_ci GFP_KERNEL); 54062306a36Sopenharmony_ci if (he_dev->tpdrq_base == NULL) { 54162306a36Sopenharmony_ci hprintk("failed to alloc tpdrq\n"); 54262306a36Sopenharmony_ci return -ENOMEM; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci he_dev->tpdrq_tail = he_dev->tpdrq_base; 54662306a36Sopenharmony_ci he_dev->tpdrq_head = he_dev->tpdrq_base; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H); 54962306a36Sopenharmony_ci he_writel(he_dev, 0, TPDRQ_T); 55062306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void he_init_cs_block(struct he_dev *he_dev) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci unsigned clock, rate, delta; 55862306a36Sopenharmony_ci int reg; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* 5.1.7 cs block initialization */ 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci for (reg = 0; reg < 0x20; ++reg) 56362306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* rate grid timer reload values */ 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci clock = he_is622(he_dev) ? 66667000 : 50000000; 56862306a36Sopenharmony_ci rate = he_dev->atm_dev->link_rate; 56962306a36Sopenharmony_ci delta = rate / 16 / 2; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci for (reg = 0; reg < 0x10; ++reg) { 57262306a36Sopenharmony_ci /* 2.4 internal transmit function 57362306a36Sopenharmony_ci * 57462306a36Sopenharmony_ci * we initialize the first row in the rate grid. 57562306a36Sopenharmony_ci * values are period (in clock cycles) of timer 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci unsigned period = clock / rate; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci he_writel_mbox(he_dev, period, CS_TGRLD0 + reg); 58062306a36Sopenharmony_ci rate -= delta; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (he_is622(he_dev)) { 58462306a36Sopenharmony_ci /* table 5.2 (4 cells per lbuf) */ 58562306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0); 58662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1); 58762306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2); 58862306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3); 58962306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ 59262306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0); 59362306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x1801, CS_ERCTL1); 59462306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2); 59562306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); 59662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1); 59762306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x14585, CS_RTFWR); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x4680, CS_RTATR); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* table 5.8 */ 60262306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET); 60362306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX); 60462306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN); 60562306a36Sopenharmony_ci he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC); 60662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC); 60762306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* table 5.9 */ 61062306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x5, CS_OTPPER); 61162306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x14, CS_OTWPER); 61262306a36Sopenharmony_ci } else { 61362306a36Sopenharmony_ci /* table 5.1 (4 cells per lbuf) */ 61462306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0); 61562306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1); 61662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2); 61762306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3); 61862306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ 62162306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0); 62262306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x4701, CS_ERCTL1); 62362306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2); 62462306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); 62562306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1); 62662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0xf424, CS_RTFWR); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x4680, CS_RTATR); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* table 5.8 */ 63162306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET); 63262306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX); 63362306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN); 63462306a36Sopenharmony_ci he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC); 63562306a36Sopenharmony_ci he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC); 63662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* table 5.9 */ 63962306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x6, CS_OTPPER); 64062306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x1e, CS_OTWPER); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x8, CS_OTTLIM); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci for (reg = 0; reg < 0x8; ++reg) 64662306a36Sopenharmony_ci he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic int he_init_cs_block_rcm(struct he_dev *he_dev) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci unsigned (*rategrid)[16][16]; 65362306a36Sopenharmony_ci unsigned rate, delta; 65462306a36Sopenharmony_ci int i, j, reg; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci unsigned rate_atmf, exp, man; 65762306a36Sopenharmony_ci unsigned long long rate_cps; 65862306a36Sopenharmony_ci int mult, buf, buf_limit = 4; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL); 66162306a36Sopenharmony_ci if (!rategrid) 66262306a36Sopenharmony_ci return -ENOMEM; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* initialize rate grid group table */ 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci for (reg = 0x0; reg < 0xff; ++reg) 66762306a36Sopenharmony_ci he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* initialize rate controller groups */ 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci for (reg = 0x100; reg < 0x1ff; ++reg) 67262306a36Sopenharmony_ci he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* initialize tNrm lookup table */ 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* the manual makes reference to a routine in a sample driver 67762306a36Sopenharmony_ci for proper configuration; fortunately, we only need this 67862306a36Sopenharmony_ci in order to support abr connection */ 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* initialize rate to group table */ 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci rate = he_dev->atm_dev->link_rate; 68362306a36Sopenharmony_ci delta = rate / 32; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* 68662306a36Sopenharmony_ci * 2.4 transmit internal functions 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * we construct a copy of the rate grid used by the scheduler 68962306a36Sopenharmony_ci * in order to construct the rate to group table below 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci for (j = 0; j < 16; j++) { 69362306a36Sopenharmony_ci (*rategrid)[0][j] = rate; 69462306a36Sopenharmony_ci rate -= delta; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci for (i = 1; i < 16; i++) 69862306a36Sopenharmony_ci for (j = 0; j < 16; j++) 69962306a36Sopenharmony_ci if (i > 14) 70062306a36Sopenharmony_ci (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 4; 70162306a36Sopenharmony_ci else 70262306a36Sopenharmony_ci (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 2; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* 70562306a36Sopenharmony_ci * 2.4 transmit internal function 70662306a36Sopenharmony_ci * 70762306a36Sopenharmony_ci * this table maps the upper 5 bits of exponent and mantissa 70862306a36Sopenharmony_ci * of the atm forum representation of the rate into an index 70962306a36Sopenharmony_ci * on rate grid 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci rate_atmf = 0; 71362306a36Sopenharmony_ci while (rate_atmf < 0x400) { 71462306a36Sopenharmony_ci man = (rate_atmf & 0x1f) << 4; 71562306a36Sopenharmony_ci exp = rate_atmf >> 5; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* 71862306a36Sopenharmony_ci instead of '/ 512', use '>> 9' to prevent a call 71962306a36Sopenharmony_ci to divdu3 on x86 platforms 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci rate_cps = (unsigned long long) (1UL << exp) * (man + 512) >> 9; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (rate_cps < 10) 72462306a36Sopenharmony_ci rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */ 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci for (i = 255; i > 0; i--) 72762306a36Sopenharmony_ci if ((*rategrid)[i/16][i%16] >= rate_cps) 72862306a36Sopenharmony_ci break; /* pick nearest rate instead? */ 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* 73162306a36Sopenharmony_ci * each table entry is 16 bits: (rate grid index (8 bits) 73262306a36Sopenharmony_ci * and a buffer limit (8 bits) 73362306a36Sopenharmony_ci * there are two table entries in each 32-bit register 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci#ifdef notdef 73762306a36Sopenharmony_ci buf = rate_cps * he_dev->tx_numbuffs / 73862306a36Sopenharmony_ci (he_dev->atm_dev->link_rate * 2); 73962306a36Sopenharmony_ci#else 74062306a36Sopenharmony_ci /* this is pretty, but avoids _divdu3 and is mostly correct */ 74162306a36Sopenharmony_ci mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; 74262306a36Sopenharmony_ci if (rate_cps > (272ULL * mult)) 74362306a36Sopenharmony_ci buf = 4; 74462306a36Sopenharmony_ci else if (rate_cps > (204ULL * mult)) 74562306a36Sopenharmony_ci buf = 3; 74662306a36Sopenharmony_ci else if (rate_cps > (136ULL * mult)) 74762306a36Sopenharmony_ci buf = 2; 74862306a36Sopenharmony_ci else if (rate_cps > (68ULL * mult)) 74962306a36Sopenharmony_ci buf = 1; 75062306a36Sopenharmony_ci else 75162306a36Sopenharmony_ci buf = 0; 75262306a36Sopenharmony_ci#endif 75362306a36Sopenharmony_ci if (buf > buf_limit) 75462306a36Sopenharmony_ci buf = buf_limit; 75562306a36Sopenharmony_ci reg = (reg << 16) | ((i << 8) | buf); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci#define RTGTBL_OFFSET 0x400 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (rate_atmf & 0x1) 76062306a36Sopenharmony_ci he_writel_rcm(he_dev, reg, 76162306a36Sopenharmony_ci CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf >> 1)); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ++rate_atmf; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci kfree(rategrid); 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic int he_init_group(struct he_dev *he_dev, int group) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct he_buff *heb, *next; 77362306a36Sopenharmony_ci dma_addr_t mapping; 77462306a36Sopenharmony_ci int i; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); 77762306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); 77862306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); 77962306a36Sopenharmony_ci he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), 78062306a36Sopenharmony_ci G0_RBPS_BS + (group * 32)); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* bitmap table */ 78362306a36Sopenharmony_ci he_dev->rbpl_table = bitmap_zalloc(RBPL_TABLE_SIZE, GFP_KERNEL); 78462306a36Sopenharmony_ci if (!he_dev->rbpl_table) { 78562306a36Sopenharmony_ci hprintk("unable to allocate rbpl bitmap table\n"); 78662306a36Sopenharmony_ci return -ENOMEM; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* rbpl_virt 64-bit pointers */ 79062306a36Sopenharmony_ci he_dev->rbpl_virt = kmalloc_array(RBPL_TABLE_SIZE, 79162306a36Sopenharmony_ci sizeof(*he_dev->rbpl_virt), 79262306a36Sopenharmony_ci GFP_KERNEL); 79362306a36Sopenharmony_ci if (!he_dev->rbpl_virt) { 79462306a36Sopenharmony_ci hprintk("unable to allocate rbpl virt table\n"); 79562306a36Sopenharmony_ci goto out_free_rbpl_table; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* large buffer pool */ 79962306a36Sopenharmony_ci he_dev->rbpl_pool = dma_pool_create("rbpl", &he_dev->pci_dev->dev, 80062306a36Sopenharmony_ci CONFIG_RBPL_BUFSIZE, 64, 0); 80162306a36Sopenharmony_ci if (he_dev->rbpl_pool == NULL) { 80262306a36Sopenharmony_ci hprintk("unable to create rbpl pool\n"); 80362306a36Sopenharmony_ci goto out_free_rbpl_virt; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci he_dev->rbpl_base = dma_alloc_coherent(&he_dev->pci_dev->dev, 80762306a36Sopenharmony_ci CONFIG_RBPL_SIZE * sizeof(struct he_rbp), 80862306a36Sopenharmony_ci &he_dev->rbpl_phys, GFP_KERNEL); 80962306a36Sopenharmony_ci if (he_dev->rbpl_base == NULL) { 81062306a36Sopenharmony_ci hprintk("failed to alloc rbpl_base\n"); 81162306a36Sopenharmony_ci goto out_destroy_rbpl_pool; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci INIT_LIST_HEAD(&he_dev->rbpl_outstanding); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL, &mapping); 81962306a36Sopenharmony_ci if (!heb) 82062306a36Sopenharmony_ci goto out_free_rbpl; 82162306a36Sopenharmony_ci heb->mapping = mapping; 82262306a36Sopenharmony_ci list_add(&heb->entry, &he_dev->rbpl_outstanding); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci set_bit(i, he_dev->rbpl_table); 82562306a36Sopenharmony_ci he_dev->rbpl_virt[i] = heb; 82662306a36Sopenharmony_ci he_dev->rbpl_hint = i + 1; 82762306a36Sopenharmony_ci he_dev->rbpl_base[i].idx = i << RBP_IDX_OFFSET; 82862306a36Sopenharmony_ci he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1]; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); 83362306a36Sopenharmony_ci he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), 83462306a36Sopenharmony_ci G0_RBPL_T + (group * 32)); 83562306a36Sopenharmony_ci he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4, 83662306a36Sopenharmony_ci G0_RBPL_BS + (group * 32)); 83762306a36Sopenharmony_ci he_writel(he_dev, 83862306a36Sopenharmony_ci RBP_THRESH(CONFIG_RBPL_THRESH) | 83962306a36Sopenharmony_ci RBP_QSIZE(CONFIG_RBPL_SIZE - 1) | 84062306a36Sopenharmony_ci RBP_INT_ENB, 84162306a36Sopenharmony_ci G0_RBPL_QI + (group * 32)); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* rx buffer ready queue */ 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci he_dev->rbrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, 84662306a36Sopenharmony_ci CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), 84762306a36Sopenharmony_ci &he_dev->rbrq_phys, GFP_KERNEL); 84862306a36Sopenharmony_ci if (he_dev->rbrq_base == NULL) { 84962306a36Sopenharmony_ci hprintk("failed to allocate rbrq\n"); 85062306a36Sopenharmony_ci goto out_free_rbpl; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci he_dev->rbrq_head = he_dev->rbrq_base; 85462306a36Sopenharmony_ci he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16)); 85562306a36Sopenharmony_ci he_writel(he_dev, 0, G0_RBRQ_H + (group * 16)); 85662306a36Sopenharmony_ci he_writel(he_dev, 85762306a36Sopenharmony_ci RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE - 1), 85862306a36Sopenharmony_ci G0_RBRQ_Q + (group * 16)); 85962306a36Sopenharmony_ci if (irq_coalesce) { 86062306a36Sopenharmony_ci hprintk("coalescing interrupts\n"); 86162306a36Sopenharmony_ci he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7), 86262306a36Sopenharmony_ci G0_RBRQ_I + (group * 16)); 86362306a36Sopenharmony_ci } else 86462306a36Sopenharmony_ci he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1), 86562306a36Sopenharmony_ci G0_RBRQ_I + (group * 16)); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* tx buffer ready queue */ 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci he_dev->tbrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, 87062306a36Sopenharmony_ci CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), 87162306a36Sopenharmony_ci &he_dev->tbrq_phys, GFP_KERNEL); 87262306a36Sopenharmony_ci if (he_dev->tbrq_base == NULL) { 87362306a36Sopenharmony_ci hprintk("failed to allocate tbrq\n"); 87462306a36Sopenharmony_ci goto out_free_rbpq_base; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci he_dev->tbrq_head = he_dev->tbrq_base; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci he_writel(he_dev, he_dev->tbrq_phys, G0_TBRQ_B_T + (group * 16)); 88062306a36Sopenharmony_ci he_writel(he_dev, 0, G0_TBRQ_H + (group * 16)); 88162306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TBRQ_SIZE - 1, G0_TBRQ_S + (group * 16)); 88262306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16)); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return 0; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ciout_free_rbpq_base: 88762306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * 88862306a36Sopenharmony_ci sizeof(struct he_rbrq), he_dev->rbrq_base, 88962306a36Sopenharmony_ci he_dev->rbrq_phys); 89062306a36Sopenharmony_ciout_free_rbpl: 89162306a36Sopenharmony_ci list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) 89262306a36Sopenharmony_ci dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE * 89562306a36Sopenharmony_ci sizeof(struct he_rbp), he_dev->rbpl_base, 89662306a36Sopenharmony_ci he_dev->rbpl_phys); 89762306a36Sopenharmony_ciout_destroy_rbpl_pool: 89862306a36Sopenharmony_ci dma_pool_destroy(he_dev->rbpl_pool); 89962306a36Sopenharmony_ciout_free_rbpl_virt: 90062306a36Sopenharmony_ci kfree(he_dev->rbpl_virt); 90162306a36Sopenharmony_ciout_free_rbpl_table: 90262306a36Sopenharmony_ci bitmap_free(he_dev->rbpl_table); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci return -ENOMEM; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int he_init_irq(struct he_dev *he_dev) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci int i; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* 2.9.3.5 tail offset for each interrupt queue is located after the 91262306a36Sopenharmony_ci end of the interrupt queue */ 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci he_dev->irq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, 91562306a36Sopenharmony_ci (CONFIG_IRQ_SIZE + 1) * sizeof(struct he_irq), 91662306a36Sopenharmony_ci &he_dev->irq_phys, GFP_KERNEL); 91762306a36Sopenharmony_ci if (he_dev->irq_base == NULL) { 91862306a36Sopenharmony_ci hprintk("failed to allocate irq\n"); 91962306a36Sopenharmony_ci return -ENOMEM; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci he_dev->irq_tailoffset = (unsigned *) 92262306a36Sopenharmony_ci &he_dev->irq_base[CONFIG_IRQ_SIZE]; 92362306a36Sopenharmony_ci *he_dev->irq_tailoffset = 0; 92462306a36Sopenharmony_ci he_dev->irq_head = he_dev->irq_base; 92562306a36Sopenharmony_ci he_dev->irq_tail = he_dev->irq_base; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci for (i = 0; i < CONFIG_IRQ_SIZE; ++i) 92862306a36Sopenharmony_ci he_dev->irq_base[i].isw = ITYPE_INVALID; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE); 93162306a36Sopenharmony_ci he_writel(he_dev, 93262306a36Sopenharmony_ci IRQ_SIZE(CONFIG_IRQ_SIZE) | IRQ_THRESH(CONFIG_IRQ_THRESH), 93362306a36Sopenharmony_ci IRQ0_HEAD); 93462306a36Sopenharmony_ci he_writel(he_dev, IRQ_INT_A | IRQ_TYPE_LINE, IRQ0_CNTL); 93562306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ0_DATA); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ1_BASE); 93862306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ1_HEAD); 93962306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ1_CNTL); 94062306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ1_DATA); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ2_BASE); 94362306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ2_HEAD); 94462306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ2_CNTL); 94562306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ2_DATA); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ3_BASE); 94862306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ3_HEAD); 94962306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ3_CNTL); 95062306a36Sopenharmony_ci he_writel(he_dev, 0x0, IRQ3_DATA); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* 2.9.3.2 interrupt queue mapping registers */ 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci he_writel(he_dev, 0x0, GRP_10_MAP); 95562306a36Sopenharmony_ci he_writel(he_dev, 0x0, GRP_32_MAP); 95662306a36Sopenharmony_ci he_writel(he_dev, 0x0, GRP_54_MAP); 95762306a36Sopenharmony_ci he_writel(he_dev, 0x0, GRP_76_MAP); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (request_irq(he_dev->pci_dev->irq, 96062306a36Sopenharmony_ci he_irq_handler, IRQF_SHARED, DEV_LABEL, he_dev)) { 96162306a36Sopenharmony_ci hprintk("irq %d already in use\n", he_dev->pci_dev->irq); 96262306a36Sopenharmony_ci return -EINVAL; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci he_dev->irq = he_dev->pci_dev->irq; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci return 0; 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic int he_start(struct atm_dev *dev) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct he_dev *he_dev; 97362306a36Sopenharmony_ci struct pci_dev *pci_dev; 97462306a36Sopenharmony_ci unsigned long membase; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci u16 command; 97762306a36Sopenharmony_ci u32 gen_cntl_0, host_cntl, lb_swap; 97862306a36Sopenharmony_ci u8 cache_size, timer; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci unsigned err; 98162306a36Sopenharmony_ci unsigned int status, reg; 98262306a36Sopenharmony_ci int i, group; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci he_dev = HE_DEV(dev); 98562306a36Sopenharmony_ci pci_dev = he_dev->pci_dev; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci membase = pci_resource_start(pci_dev, 0); 98862306a36Sopenharmony_ci HPRINTK("membase = 0x%lx irq = %d.\n", membase, pci_dev->irq); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* 99162306a36Sopenharmony_ci * pci bus controller initialization 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* 4.3 pci bus controller-specific initialization */ 99562306a36Sopenharmony_ci if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) { 99662306a36Sopenharmony_ci hprintk("can't read GEN_CNTL_0\n"); 99762306a36Sopenharmony_ci return -EINVAL; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT); 100062306a36Sopenharmony_ci if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) { 100162306a36Sopenharmony_ci hprintk("can't write GEN_CNTL_0.\n"); 100262306a36Sopenharmony_ci return -EINVAL; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) { 100662306a36Sopenharmony_ci hprintk("can't read PCI_COMMAND.\n"); 100762306a36Sopenharmony_ci return -EINVAL; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); 101162306a36Sopenharmony_ci if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) { 101262306a36Sopenharmony_ci hprintk("can't enable memory.\n"); 101362306a36Sopenharmony_ci return -EINVAL; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) { 101762306a36Sopenharmony_ci hprintk("can't read cache line size?\n"); 101862306a36Sopenharmony_ci return -EINVAL; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (cache_size < 16) { 102262306a36Sopenharmony_ci cache_size = 16; 102362306a36Sopenharmony_ci if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size)) 102462306a36Sopenharmony_ci hprintk("can't set cache line size to %d\n", cache_size); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) { 102862306a36Sopenharmony_ci hprintk("can't read latency timer?\n"); 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* from table 3.9 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * LAT_TIMER = 1 + AVG_LAT + BURST_SIZE/BUS_SIZE 103562306a36Sopenharmony_ci * 103662306a36Sopenharmony_ci * AVG_LAT: The average first data read/write latency [maximum 16 clock cycles] 103762306a36Sopenharmony_ci * BURST_SIZE: 1536 bytes (read) for 622, 768 bytes (read) for 155 [192 clock cycles] 103862306a36Sopenharmony_ci * 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci#define LAT_TIMER 209 104162306a36Sopenharmony_ci if (timer < LAT_TIMER) { 104262306a36Sopenharmony_ci HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER); 104362306a36Sopenharmony_ci timer = LAT_TIMER; 104462306a36Sopenharmony_ci if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer)) 104562306a36Sopenharmony_ci hprintk("can't set latency timer to %d\n", timer); 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (!(he_dev->membase = ioremap(membase, HE_REGMAP_SIZE))) { 104962306a36Sopenharmony_ci hprintk("can't set up page mapping\n"); 105062306a36Sopenharmony_ci return -EINVAL; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* 4.4 card reset */ 105462306a36Sopenharmony_ci he_writel(he_dev, 0x0, RESET_CNTL); 105562306a36Sopenharmony_ci he_writel(he_dev, 0xff, RESET_CNTL); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci msleep(16); /* 16 ms */ 105862306a36Sopenharmony_ci status = he_readl(he_dev, RESET_CNTL); 105962306a36Sopenharmony_ci if ((status & BOARD_RST_STATUS) == 0) { 106062306a36Sopenharmony_ci hprintk("reset failed\n"); 106162306a36Sopenharmony_ci return -EINVAL; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci /* 4.5 set bus width */ 106562306a36Sopenharmony_ci host_cntl = he_readl(he_dev, HOST_CNTL); 106662306a36Sopenharmony_ci if (host_cntl & PCI_BUS_SIZE64) 106762306a36Sopenharmony_ci gen_cntl_0 |= ENBL_64; 106862306a36Sopenharmony_ci else 106962306a36Sopenharmony_ci gen_cntl_0 &= ~ENBL_64; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (disable64 == 1) { 107262306a36Sopenharmony_ci hprintk("disabling 64-bit pci bus transfers\n"); 107362306a36Sopenharmony_ci gen_cntl_0 &= ~ENBL_64; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (gen_cntl_0 & ENBL_64) 107762306a36Sopenharmony_ci hprintk("64-bit transfers enabled\n"); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* 4.7 read prom contents */ 108262306a36Sopenharmony_ci for (i = 0; i < PROD_ID_LEN; ++i) 108362306a36Sopenharmony_ci he_dev->prod_id[i] = read_prom_byte(he_dev, PROD_ID + i); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci he_dev->media = read_prom_byte(he_dev, MEDIA); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci for (i = 0; i < 6; ++i) 108862306a36Sopenharmony_ci dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci hprintk("%s%s, %pM\n", he_dev->prod_id, 109162306a36Sopenharmony_ci he_dev->media & 0x40 ? "SM" : "MM", dev->esi); 109262306a36Sopenharmony_ci he_dev->atm_dev->link_rate = he_is622(he_dev) ? 109362306a36Sopenharmony_ci ATM_OC12_PCR : ATM_OC3_PCR; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* 4.6 set host endianess */ 109662306a36Sopenharmony_ci lb_swap = he_readl(he_dev, LB_SWAP); 109762306a36Sopenharmony_ci if (he_is622(he_dev)) 109862306a36Sopenharmony_ci lb_swap &= ~XFER_SIZE; /* 4 cells */ 109962306a36Sopenharmony_ci else 110062306a36Sopenharmony_ci lb_swap |= XFER_SIZE; /* 8 cells */ 110162306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 110262306a36Sopenharmony_ci lb_swap |= DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST; 110362306a36Sopenharmony_ci#else 110462306a36Sopenharmony_ci lb_swap &= ~(DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST | 110562306a36Sopenharmony_ci DATA_WR_SWAP | DATA_RD_SWAP | DESC_RD_SWAP); 110662306a36Sopenharmony_ci#endif /* __BIG_ENDIAN */ 110762306a36Sopenharmony_ci he_writel(he_dev, lb_swap, LB_SWAP); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* 4.8 sdram controller initialization */ 111062306a36Sopenharmony_ci he_writel(he_dev, he_is622(he_dev) ? LB_64_ENB : 0x0, SDRAM_CTL); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* 4.9 initialize rnum value */ 111362306a36Sopenharmony_ci lb_swap |= SWAP_RNUM_MAX(0xf); 111462306a36Sopenharmony_ci he_writel(he_dev, lb_swap, LB_SWAP); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* 4.10 initialize the interrupt queues */ 111762306a36Sopenharmony_ci if ((err = he_init_irq(he_dev)) != 0) 111862306a36Sopenharmony_ci return err; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* 4.11 enable pci bus controller state machines */ 112162306a36Sopenharmony_ci host_cntl |= (OUTFF_ENB | CMDFF_ENB | 112262306a36Sopenharmony_ci QUICK_RD_RETRY | QUICK_WR_RETRY | PERR_INT_ENB); 112362306a36Sopenharmony_ci he_writel(he_dev, host_cntl, HOST_CNTL); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci gen_cntl_0 |= INT_PROC_ENBL|INIT_ENB; 112662306a36Sopenharmony_ci pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* 112962306a36Sopenharmony_ci * atm network controller initialization 113062306a36Sopenharmony_ci */ 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* 5.1.1 generic configuration state */ 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci /* 113562306a36Sopenharmony_ci * local (cell) buffer memory map 113662306a36Sopenharmony_ci * 113762306a36Sopenharmony_ci * HE155 HE622 113862306a36Sopenharmony_ci * 113962306a36Sopenharmony_ci * 0 ____________1023 bytes 0 _______________________2047 bytes 114062306a36Sopenharmony_ci * | | | | | 114162306a36Sopenharmony_ci * | utility | | rx0 | | 114262306a36Sopenharmony_ci * 5|____________| 255|___________________| u | 114362306a36Sopenharmony_ci * 6| | 256| | t | 114462306a36Sopenharmony_ci * | | | | i | 114562306a36Sopenharmony_ci * | rx0 | row | tx | l | 114662306a36Sopenharmony_ci * | | | | i | 114762306a36Sopenharmony_ci * | | 767|___________________| t | 114862306a36Sopenharmony_ci * 517|____________| 768| | y | 114962306a36Sopenharmony_ci * row 518| | | rx1 | | 115062306a36Sopenharmony_ci * | | 1023|___________________|___| 115162306a36Sopenharmony_ci * | | 115262306a36Sopenharmony_ci * | tx | 115362306a36Sopenharmony_ci * | | 115462306a36Sopenharmony_ci * | | 115562306a36Sopenharmony_ci * 1535|____________| 115662306a36Sopenharmony_ci * 1536| | 115762306a36Sopenharmony_ci * | rx1 | 115862306a36Sopenharmony_ci * 2047|____________| 115962306a36Sopenharmony_ci * 116062306a36Sopenharmony_ci */ 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci /* total 4096 connections */ 116362306a36Sopenharmony_ci he_dev->vcibits = CONFIG_DEFAULT_VCIBITS; 116462306a36Sopenharmony_ci he_dev->vpibits = CONFIG_DEFAULT_VPIBITS; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) { 116762306a36Sopenharmony_ci hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS); 116862306a36Sopenharmony_ci return -ENODEV; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (nvpibits != -1) { 117262306a36Sopenharmony_ci he_dev->vpibits = nvpibits; 117362306a36Sopenharmony_ci he_dev->vcibits = HE_MAXCIDBITS - nvpibits; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (nvcibits != -1) { 117762306a36Sopenharmony_ci he_dev->vcibits = nvcibits; 117862306a36Sopenharmony_ci he_dev->vpibits = HE_MAXCIDBITS - nvcibits; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (he_is622(he_dev)) { 118362306a36Sopenharmony_ci he_dev->cells_per_row = 40; 118462306a36Sopenharmony_ci he_dev->bytes_per_row = 2048; 118562306a36Sopenharmony_ci he_dev->r0_numrows = 256; 118662306a36Sopenharmony_ci he_dev->tx_numrows = 512; 118762306a36Sopenharmony_ci he_dev->r1_numrows = 256; 118862306a36Sopenharmony_ci he_dev->r0_startrow = 0; 118962306a36Sopenharmony_ci he_dev->tx_startrow = 256; 119062306a36Sopenharmony_ci he_dev->r1_startrow = 768; 119162306a36Sopenharmony_ci } else { 119262306a36Sopenharmony_ci he_dev->cells_per_row = 20; 119362306a36Sopenharmony_ci he_dev->bytes_per_row = 1024; 119462306a36Sopenharmony_ci he_dev->r0_numrows = 512; 119562306a36Sopenharmony_ci he_dev->tx_numrows = 1018; 119662306a36Sopenharmony_ci he_dev->r1_numrows = 512; 119762306a36Sopenharmony_ci he_dev->r0_startrow = 6; 119862306a36Sopenharmony_ci he_dev->tx_startrow = 518; 119962306a36Sopenharmony_ci he_dev->r1_startrow = 1536; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci he_dev->cells_per_lbuf = 4; 120362306a36Sopenharmony_ci he_dev->buffer_limit = 4; 120462306a36Sopenharmony_ci he_dev->r0_numbuffs = he_dev->r0_numrows * 120562306a36Sopenharmony_ci he_dev->cells_per_row / he_dev->cells_per_lbuf; 120662306a36Sopenharmony_ci if (he_dev->r0_numbuffs > 2560) 120762306a36Sopenharmony_ci he_dev->r0_numbuffs = 2560; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci he_dev->r1_numbuffs = he_dev->r1_numrows * 121062306a36Sopenharmony_ci he_dev->cells_per_row / he_dev->cells_per_lbuf; 121162306a36Sopenharmony_ci if (he_dev->r1_numbuffs > 2560) 121262306a36Sopenharmony_ci he_dev->r1_numbuffs = 2560; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci he_dev->tx_numbuffs = he_dev->tx_numrows * 121562306a36Sopenharmony_ci he_dev->cells_per_row / he_dev->cells_per_lbuf; 121662306a36Sopenharmony_ci if (he_dev->tx_numbuffs > 5120) 121762306a36Sopenharmony_ci he_dev->tx_numbuffs = 5120; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* 5.1.2 configure hardware dependent registers */ 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci he_writel(he_dev, 122262306a36Sopenharmony_ci SLICE_X(0x2) | ARB_RNUM_MAX(0xf) | TH_PRTY(0x3) | 122362306a36Sopenharmony_ci RH_PRTY(0x3) | TL_PRTY(0x2) | RL_PRTY(0x1) | 122462306a36Sopenharmony_ci (he_is622(he_dev) ? BUS_MULTI(0x28) : BUS_MULTI(0x46)) | 122562306a36Sopenharmony_ci (he_is622(he_dev) ? NET_PREF(0x50) : NET_PREF(0x8c)), 122662306a36Sopenharmony_ci LBARB); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci he_writel(he_dev, BANK_ON | 122962306a36Sopenharmony_ci (he_is622(he_dev) ? (REF_RATE(0x384) | WIDE_DATA) : REF_RATE(0x150)), 123062306a36Sopenharmony_ci SDRAMCON); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci he_writel(he_dev, 123362306a36Sopenharmony_ci (he_is622(he_dev) ? RM_BANK_WAIT(1) : RM_BANK_WAIT(0)) | 123462306a36Sopenharmony_ci RM_RW_WAIT(1), RCMCONFIG); 123562306a36Sopenharmony_ci he_writel(he_dev, 123662306a36Sopenharmony_ci (he_is622(he_dev) ? TM_BANK_WAIT(2) : TM_BANK_WAIT(1)) | 123762306a36Sopenharmony_ci TM_RW_WAIT(1), TCMCONFIG); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci he_writel(he_dev, he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD, LB_CONFIG); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci he_writel(he_dev, 124262306a36Sopenharmony_ci (he_is622(he_dev) ? UT_RD_DELAY(8) : UT_RD_DELAY(0)) | 124362306a36Sopenharmony_ci (he_is622(he_dev) ? RC_UT_MODE(0) : RC_UT_MODE(1)) | 124462306a36Sopenharmony_ci RX_VALVP(he_dev->vpibits) | 124562306a36Sopenharmony_ci RX_VALVC(he_dev->vcibits), RC_CONFIG); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci he_writel(he_dev, DRF_THRESH(0x20) | 124862306a36Sopenharmony_ci (he_is622(he_dev) ? TX_UT_MODE(0) : TX_UT_MODE(1)) | 124962306a36Sopenharmony_ci TX_VCI_MASK(he_dev->vcibits) | 125062306a36Sopenharmony_ci LBFREE_CNT(he_dev->tx_numbuffs), TX_CONFIG); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci he_writel(he_dev, 0x0, TXAAL5_PROTO); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci he_writel(he_dev, PHY_INT_ENB | 125562306a36Sopenharmony_ci (he_is622(he_dev) ? PTMR_PRE(67 - 1) : PTMR_PRE(50 - 1)), 125662306a36Sopenharmony_ci RH_CONFIG); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci /* 5.1.3 initialize connection memory */ 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci for (i = 0; i < TCM_MEM_SIZE; ++i) 126162306a36Sopenharmony_ci he_writel_tcm(he_dev, 0, i); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci for (i = 0; i < RCM_MEM_SIZE; ++i) 126462306a36Sopenharmony_ci he_writel_rcm(he_dev, 0, i); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* 126762306a36Sopenharmony_ci * transmit connection memory map 126862306a36Sopenharmony_ci * 126962306a36Sopenharmony_ci * tx memory 127062306a36Sopenharmony_ci * 0x0 ___________________ 127162306a36Sopenharmony_ci * | | 127262306a36Sopenharmony_ci * | | 127362306a36Sopenharmony_ci * | TSRa | 127462306a36Sopenharmony_ci * | | 127562306a36Sopenharmony_ci * | | 127662306a36Sopenharmony_ci * 0x8000|___________________| 127762306a36Sopenharmony_ci * | | 127862306a36Sopenharmony_ci * | TSRb | 127962306a36Sopenharmony_ci * 0xc000|___________________| 128062306a36Sopenharmony_ci * | | 128162306a36Sopenharmony_ci * | TSRc | 128262306a36Sopenharmony_ci * 0xe000|___________________| 128362306a36Sopenharmony_ci * | TSRd | 128462306a36Sopenharmony_ci * 0xf000|___________________| 128562306a36Sopenharmony_ci * | tmABR | 128662306a36Sopenharmony_ci * 0x10000|___________________| 128762306a36Sopenharmony_ci * | | 128862306a36Sopenharmony_ci * | tmTPD | 128962306a36Sopenharmony_ci * |___________________| 129062306a36Sopenharmony_ci * | | 129162306a36Sopenharmony_ci * .... 129262306a36Sopenharmony_ci * 0x1ffff|___________________| 129362306a36Sopenharmony_ci * 129462306a36Sopenharmony_ci * 129562306a36Sopenharmony_ci */ 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TSRB, TSRB_BA); 129862306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TSRC, TSRC_BA); 129962306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TSRD, TSRD_BA); 130062306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TMABR, TMABR_BA); 130162306a36Sopenharmony_ci he_writel(he_dev, CONFIG_TPDBA, TPD_BA); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* 130562306a36Sopenharmony_ci * receive connection memory map 130662306a36Sopenharmony_ci * 130762306a36Sopenharmony_ci * 0x0 ___________________ 130862306a36Sopenharmony_ci * | | 130962306a36Sopenharmony_ci * | | 131062306a36Sopenharmony_ci * | RSRa | 131162306a36Sopenharmony_ci * | | 131262306a36Sopenharmony_ci * | | 131362306a36Sopenharmony_ci * 0x8000|___________________| 131462306a36Sopenharmony_ci * | | 131562306a36Sopenharmony_ci * | rx0/1 | 131662306a36Sopenharmony_ci * | LBM | link lists of local 131762306a36Sopenharmony_ci * | tx | buffer memory 131862306a36Sopenharmony_ci * | | 131962306a36Sopenharmony_ci * 0xd000|___________________| 132062306a36Sopenharmony_ci * | | 132162306a36Sopenharmony_ci * | rmABR | 132262306a36Sopenharmony_ci * 0xe000|___________________| 132362306a36Sopenharmony_ci * | | 132462306a36Sopenharmony_ci * | RSRb | 132562306a36Sopenharmony_ci * |___________________| 132662306a36Sopenharmony_ci * | | 132762306a36Sopenharmony_ci * .... 132862306a36Sopenharmony_ci * 0xffff|___________________| 132962306a36Sopenharmony_ci */ 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci he_writel(he_dev, 0x08000, RCMLBM_BA); 133262306a36Sopenharmony_ci he_writel(he_dev, 0x0e000, RCMRSRB_BA); 133362306a36Sopenharmony_ci he_writel(he_dev, 0x0d800, RCMABR_BA); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* 5.1.4 initialize local buffer free pools linked lists */ 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci he_init_rx_lbfp0(he_dev); 133862306a36Sopenharmony_ci he_init_rx_lbfp1(he_dev); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci he_writel(he_dev, 0x0, RLBC_H); 134162306a36Sopenharmony_ci he_writel(he_dev, 0x0, RLBC_T); 134262306a36Sopenharmony_ci he_writel(he_dev, 0x0, RLBC_H2); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci he_writel(he_dev, 512, RXTHRSH); /* 10% of r0+r1 buffers */ 134562306a36Sopenharmony_ci he_writel(he_dev, 256, LITHRSH); /* 5% of r0+r1 buffers */ 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci he_init_tx_lbfp(he_dev); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci he_writel(he_dev, he_is622(he_dev) ? 0x104780 : 0x800, UBUFF_BA); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* 5.1.5 initialize intermediate receive queues */ 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (he_is622(he_dev)) { 135462306a36Sopenharmony_ci he_writel(he_dev, 0x000f, G0_INMQ_S); 135562306a36Sopenharmony_ci he_writel(he_dev, 0x200f, G0_INMQ_L); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci he_writel(he_dev, 0x001f, G1_INMQ_S); 135862306a36Sopenharmony_ci he_writel(he_dev, 0x201f, G1_INMQ_L); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci he_writel(he_dev, 0x002f, G2_INMQ_S); 136162306a36Sopenharmony_ci he_writel(he_dev, 0x202f, G2_INMQ_L); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci he_writel(he_dev, 0x003f, G3_INMQ_S); 136462306a36Sopenharmony_ci he_writel(he_dev, 0x203f, G3_INMQ_L); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci he_writel(he_dev, 0x004f, G4_INMQ_S); 136762306a36Sopenharmony_ci he_writel(he_dev, 0x204f, G4_INMQ_L); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci he_writel(he_dev, 0x005f, G5_INMQ_S); 137062306a36Sopenharmony_ci he_writel(he_dev, 0x205f, G5_INMQ_L); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci he_writel(he_dev, 0x006f, G6_INMQ_S); 137362306a36Sopenharmony_ci he_writel(he_dev, 0x206f, G6_INMQ_L); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci he_writel(he_dev, 0x007f, G7_INMQ_S); 137662306a36Sopenharmony_ci he_writel(he_dev, 0x207f, G7_INMQ_L); 137762306a36Sopenharmony_ci } else { 137862306a36Sopenharmony_ci he_writel(he_dev, 0x0000, G0_INMQ_S); 137962306a36Sopenharmony_ci he_writel(he_dev, 0x0008, G0_INMQ_L); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci he_writel(he_dev, 0x0001, G1_INMQ_S); 138262306a36Sopenharmony_ci he_writel(he_dev, 0x0009, G1_INMQ_L); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci he_writel(he_dev, 0x0002, G2_INMQ_S); 138562306a36Sopenharmony_ci he_writel(he_dev, 0x000a, G2_INMQ_L); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci he_writel(he_dev, 0x0003, G3_INMQ_S); 138862306a36Sopenharmony_ci he_writel(he_dev, 0x000b, G3_INMQ_L); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci he_writel(he_dev, 0x0004, G4_INMQ_S); 139162306a36Sopenharmony_ci he_writel(he_dev, 0x000c, G4_INMQ_L); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci he_writel(he_dev, 0x0005, G5_INMQ_S); 139462306a36Sopenharmony_ci he_writel(he_dev, 0x000d, G5_INMQ_L); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci he_writel(he_dev, 0x0006, G6_INMQ_S); 139762306a36Sopenharmony_ci he_writel(he_dev, 0x000e, G6_INMQ_L); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci he_writel(he_dev, 0x0007, G7_INMQ_S); 140062306a36Sopenharmony_ci he_writel(he_dev, 0x000f, G7_INMQ_L); 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* 5.1.6 application tunable parameters */ 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci he_writel(he_dev, 0x0, MCC); 140662306a36Sopenharmony_ci he_writel(he_dev, 0x0, OEC); 140762306a36Sopenharmony_ci he_writel(he_dev, 0x0, DCC); 140862306a36Sopenharmony_ci he_writel(he_dev, 0x0, CEC); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci /* 5.1.7 cs block initialization */ 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci he_init_cs_block(he_dev); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* 5.1.8 cs block connection memory initialization */ 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (he_init_cs_block_rcm(he_dev) < 0) 141762306a36Sopenharmony_ci return -ENOMEM; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* 5.1.10 initialize host structures */ 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci he_init_tpdrq(he_dev); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci he_dev->tpd_pool = dma_pool_create("tpd", &he_dev->pci_dev->dev, 142462306a36Sopenharmony_ci sizeof(struct he_tpd), TPD_ALIGNMENT, 0); 142562306a36Sopenharmony_ci if (he_dev->tpd_pool == NULL) { 142662306a36Sopenharmony_ci hprintk("unable to create tpd dma_pool\n"); 142762306a36Sopenharmony_ci return -ENOMEM; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci INIT_LIST_HEAD(&he_dev->outstanding_tpds); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci if (he_init_group(he_dev, 0) != 0) 143362306a36Sopenharmony_ci return -ENOMEM; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci for (group = 1; group < HE_NUM_GROUPS; ++group) { 143662306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); 143762306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); 143862306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); 143962306a36Sopenharmony_ci he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), 144062306a36Sopenharmony_ci G0_RBPS_BS + (group * 32)); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPL_S + (group * 32)); 144362306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPL_T + (group * 32)); 144462306a36Sopenharmony_ci he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), 144562306a36Sopenharmony_ci G0_RBPL_QI + (group * 32)); 144662306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBPL_BS + (group * 32)); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBRQ_ST + (group * 16)); 144962306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBRQ_H + (group * 16)); 145062306a36Sopenharmony_ci he_writel(he_dev, RBRQ_THRESH(0x1) | RBRQ_SIZE(0x0), 145162306a36Sopenharmony_ci G0_RBRQ_Q + (group * 16)); 145262306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_RBRQ_I + (group * 16)); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_TBRQ_B_T + (group * 16)); 145562306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_TBRQ_H + (group * 16)); 145662306a36Sopenharmony_ci he_writel(he_dev, TBRQ_THRESH(0x1), 145762306a36Sopenharmony_ci G0_TBRQ_THRESH + (group * 16)); 145862306a36Sopenharmony_ci he_writel(he_dev, 0x0, G0_TBRQ_S + (group * 16)); 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* host status page */ 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci he_dev->hsp = dma_alloc_coherent(&he_dev->pci_dev->dev, 146462306a36Sopenharmony_ci sizeof(struct he_hsp), 146562306a36Sopenharmony_ci &he_dev->hsp_phys, GFP_KERNEL); 146662306a36Sopenharmony_ci if (he_dev->hsp == NULL) { 146762306a36Sopenharmony_ci hprintk("failed to allocate host status page\n"); 146862306a36Sopenharmony_ci return -ENOMEM; 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci he_writel(he_dev, he_dev->hsp_phys, HSP_BA); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci /* initialize framer */ 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci#ifdef CONFIG_ATM_HE_USE_SUNI 147562306a36Sopenharmony_ci if (he_isMM(he_dev)) 147662306a36Sopenharmony_ci suni_init(he_dev->atm_dev); 147762306a36Sopenharmony_ci if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start) 147862306a36Sopenharmony_ci he_dev->atm_dev->phy->start(he_dev->atm_dev); 147962306a36Sopenharmony_ci#endif /* CONFIG_ATM_HE_USE_SUNI */ 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if (sdh) { 148262306a36Sopenharmony_ci /* this really should be in suni.c but for now... */ 148362306a36Sopenharmony_ci int val; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM); 148662306a36Sopenharmony_ci val = (val & ~SUNI_TPOP_APM_S) | (SUNI_TPOP_S_SDH << SUNI_TPOP_APM_S_SHIFT); 148762306a36Sopenharmony_ci he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM); 148862306a36Sopenharmony_ci he_phy_put(he_dev->atm_dev, SUNI_TACP_IUCHP_CLP, SUNI_TACP_IUCHP); 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci /* 5.1.12 enable transmit and receive */ 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci reg = he_readl_mbox(he_dev, CS_ERCTL0); 149462306a36Sopenharmony_ci reg |= TX_ENABLE|ER_ENABLE; 149562306a36Sopenharmony_ci he_writel_mbox(he_dev, reg, CS_ERCTL0); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci reg = he_readl(he_dev, RC_CONFIG); 149862306a36Sopenharmony_ci reg |= RX_ENABLE; 149962306a36Sopenharmony_ci he_writel(he_dev, reg, RC_CONFIG); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci for (i = 0; i < HE_NUM_CS_STPER; ++i) { 150262306a36Sopenharmony_ci he_dev->cs_stper[i].inuse = 0; 150362306a36Sopenharmony_ci he_dev->cs_stper[i].pcr = -1; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci he_dev->total_bw = 0; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* atm linux initialization */ 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci he_dev->atm_dev->ci_range.vpi_bits = he_dev->vpibits; 151162306a36Sopenharmony_ci he_dev->atm_dev->ci_range.vci_bits = he_dev->vcibits; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci he_dev->irq_peak = 0; 151462306a36Sopenharmony_ci he_dev->rbrq_peak = 0; 151562306a36Sopenharmony_ci he_dev->rbpl_peak = 0; 151662306a36Sopenharmony_ci he_dev->tbrq_peak = 0; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci HPRINTK("hell bent for leather!\n"); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci return 0; 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic void 152462306a36Sopenharmony_cihe_stop(struct he_dev *he_dev) 152562306a36Sopenharmony_ci{ 152662306a36Sopenharmony_ci struct he_buff *heb, *next; 152762306a36Sopenharmony_ci struct pci_dev *pci_dev; 152862306a36Sopenharmony_ci u32 gen_cntl_0, reg; 152962306a36Sopenharmony_ci u16 command; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci pci_dev = he_dev->pci_dev; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci /* disable interrupts */ 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (he_dev->membase) { 153662306a36Sopenharmony_ci pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0); 153762306a36Sopenharmony_ci gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB); 153862306a36Sopenharmony_ci pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci tasklet_disable(&he_dev->tasklet); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* disable recv and transmit */ 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci reg = he_readl_mbox(he_dev, CS_ERCTL0); 154562306a36Sopenharmony_ci reg &= ~(TX_ENABLE|ER_ENABLE); 154662306a36Sopenharmony_ci he_writel_mbox(he_dev, reg, CS_ERCTL0); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci reg = he_readl(he_dev, RC_CONFIG); 154962306a36Sopenharmony_ci reg &= ~(RX_ENABLE); 155062306a36Sopenharmony_ci he_writel(he_dev, reg, RC_CONFIG); 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci#ifdef CONFIG_ATM_HE_USE_SUNI 155462306a36Sopenharmony_ci if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->stop) 155562306a36Sopenharmony_ci he_dev->atm_dev->phy->stop(he_dev->atm_dev); 155662306a36Sopenharmony_ci#endif /* CONFIG_ATM_HE_USE_SUNI */ 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (he_dev->irq) 155962306a36Sopenharmony_ci free_irq(he_dev->irq, he_dev); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if (he_dev->irq_base) 156262306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, (CONFIG_IRQ_SIZE + 1) 156362306a36Sopenharmony_ci * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (he_dev->hsp) 156662306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, sizeof(struct he_hsp), 156762306a36Sopenharmony_ci he_dev->hsp, he_dev->hsp_phys); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (he_dev->rbpl_base) { 157062306a36Sopenharmony_ci list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) 157162306a36Sopenharmony_ci dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE 157462306a36Sopenharmony_ci * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci kfree(he_dev->rbpl_virt); 157862306a36Sopenharmony_ci bitmap_free(he_dev->rbpl_table); 157962306a36Sopenharmony_ci dma_pool_destroy(he_dev->rbpl_pool); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (he_dev->rbrq_base) 158262306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), 158362306a36Sopenharmony_ci he_dev->rbrq_base, he_dev->rbrq_phys); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (he_dev->tbrq_base) 158662306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), 158762306a36Sopenharmony_ci he_dev->tbrq_base, he_dev->tbrq_phys); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (he_dev->tpdrq_base) 159062306a36Sopenharmony_ci dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), 159162306a36Sopenharmony_ci he_dev->tpdrq_base, he_dev->tpdrq_phys); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci dma_pool_destroy(he_dev->tpd_pool); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (he_dev->pci_dev) { 159662306a36Sopenharmony_ci pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); 159762306a36Sopenharmony_ci command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); 159862306a36Sopenharmony_ci pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command); 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (he_dev->membase) 160262306a36Sopenharmony_ci iounmap(he_dev->membase); 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic struct he_tpd * 160662306a36Sopenharmony_ci__alloc_tpd(struct he_dev *he_dev) 160762306a36Sopenharmony_ci{ 160862306a36Sopenharmony_ci struct he_tpd *tpd; 160962306a36Sopenharmony_ci dma_addr_t mapping; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci tpd = dma_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC, &mapping); 161262306a36Sopenharmony_ci if (tpd == NULL) 161362306a36Sopenharmony_ci return NULL; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci tpd->status = TPD_ADDR(mapping); 161662306a36Sopenharmony_ci tpd->reserved = 0; 161762306a36Sopenharmony_ci tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0; 161862306a36Sopenharmony_ci tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0; 161962306a36Sopenharmony_ci tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return tpd; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci#define AAL5_LEN(buf,len) \ 162562306a36Sopenharmony_ci ((((unsigned char *)(buf))[(len)-6] << 8) | \ 162662306a36Sopenharmony_ci (((unsigned char *)(buf))[(len)-5])) 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci/* 2.10.1.2 receive 162962306a36Sopenharmony_ci * 163062306a36Sopenharmony_ci * aal5 packets can optionally return the tcp checksum in the lower 163162306a36Sopenharmony_ci * 16 bits of the crc (RSR0_TCP_CKSUM) 163262306a36Sopenharmony_ci */ 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci#define TCP_CKSUM(buf,len) \ 163562306a36Sopenharmony_ci ((((unsigned char *)(buf))[(len)-2] << 8) | \ 163662306a36Sopenharmony_ci (((unsigned char *)(buf))[(len-1)])) 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_cistatic int 163962306a36Sopenharmony_cihe_service_rbrq(struct he_dev *he_dev, int group) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci struct he_rbrq *rbrq_tail = (struct he_rbrq *) 164262306a36Sopenharmony_ci ((unsigned long)he_dev->rbrq_base | 164362306a36Sopenharmony_ci he_dev->hsp->group[group].rbrq_tail); 164462306a36Sopenharmony_ci unsigned cid, lastcid = -1; 164562306a36Sopenharmony_ci struct sk_buff *skb; 164662306a36Sopenharmony_ci struct atm_vcc *vcc = NULL; 164762306a36Sopenharmony_ci struct he_vcc *he_vcc; 164862306a36Sopenharmony_ci struct he_buff *heb, *next; 164962306a36Sopenharmony_ci int i; 165062306a36Sopenharmony_ci int pdus_assembled = 0; 165162306a36Sopenharmony_ci int updated = 0; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci read_lock(&vcc_sklist_lock); 165462306a36Sopenharmony_ci while (he_dev->rbrq_head != rbrq_tail) { 165562306a36Sopenharmony_ci ++updated; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n", 165862306a36Sopenharmony_ci he_dev->rbrq_head, group, 165962306a36Sopenharmony_ci RBRQ_ADDR(he_dev->rbrq_head), 166062306a36Sopenharmony_ci RBRQ_BUFLEN(he_dev->rbrq_head), 166162306a36Sopenharmony_ci RBRQ_CID(he_dev->rbrq_head), 166262306a36Sopenharmony_ci RBRQ_CRC_ERR(he_dev->rbrq_head) ? " CRC_ERR" : "", 166362306a36Sopenharmony_ci RBRQ_LEN_ERR(he_dev->rbrq_head) ? " LEN_ERR" : "", 166462306a36Sopenharmony_ci RBRQ_END_PDU(he_dev->rbrq_head) ? " END_PDU" : "", 166562306a36Sopenharmony_ci RBRQ_AAL5_PROT(he_dev->rbrq_head) ? " AAL5_PROT" : "", 166662306a36Sopenharmony_ci RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", 166762306a36Sopenharmony_ci RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET; 167062306a36Sopenharmony_ci heb = he_dev->rbpl_virt[i]; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci cid = RBRQ_CID(he_dev->rbrq_head); 167362306a36Sopenharmony_ci if (cid != lastcid) 167462306a36Sopenharmony_ci vcc = __find_vcc(he_dev, cid); 167562306a36Sopenharmony_ci lastcid = cid; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) { 167862306a36Sopenharmony_ci hprintk("vcc/he_vcc == NULL (cid 0x%x)\n", cid); 167962306a36Sopenharmony_ci if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) { 168062306a36Sopenharmony_ci clear_bit(i, he_dev->rbpl_table); 168162306a36Sopenharmony_ci list_del(&heb->entry); 168262306a36Sopenharmony_ci dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci goto next_rbrq_entry; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) { 168962306a36Sopenharmony_ci hprintk("HBUF_ERR! (cid 0x%x)\n", cid); 169062306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 169162306a36Sopenharmony_ci goto return_host_buffers; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; 169562306a36Sopenharmony_ci clear_bit(i, he_dev->rbpl_table); 169662306a36Sopenharmony_ci list_move_tail(&heb->entry, &he_vcc->buffers); 169762306a36Sopenharmony_ci he_vcc->pdu_len += heb->len; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) { 170062306a36Sopenharmony_ci lastcid = -1; 170162306a36Sopenharmony_ci HPRINTK("wake_up rx_waitq (cid 0x%x)\n", cid); 170262306a36Sopenharmony_ci wake_up(&he_vcc->rx_waitq); 170362306a36Sopenharmony_ci goto return_host_buffers; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci if (!RBRQ_END_PDU(he_dev->rbrq_head)) 170762306a36Sopenharmony_ci goto next_rbrq_entry; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (RBRQ_LEN_ERR(he_dev->rbrq_head) 171062306a36Sopenharmony_ci || RBRQ_CRC_ERR(he_dev->rbrq_head)) { 171162306a36Sopenharmony_ci HPRINTK("%s%s (%d.%d)\n", 171262306a36Sopenharmony_ci RBRQ_CRC_ERR(he_dev->rbrq_head) 171362306a36Sopenharmony_ci ? "CRC_ERR " : "", 171462306a36Sopenharmony_ci RBRQ_LEN_ERR(he_dev->rbrq_head) 171562306a36Sopenharmony_ci ? "LEN_ERR" : "", 171662306a36Sopenharmony_ci vcc->vpi, vcc->vci); 171762306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 171862306a36Sopenharmony_ci goto return_host_buffers; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve, 172262306a36Sopenharmony_ci GFP_ATOMIC); 172362306a36Sopenharmony_ci if (!skb) { 172462306a36Sopenharmony_ci HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci); 172562306a36Sopenharmony_ci goto return_host_buffers; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci if (rx_skb_reserve > 0) 172962306a36Sopenharmony_ci skb_reserve(skb, rx_skb_reserve); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci __net_timestamp(skb); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci list_for_each_entry(heb, &he_vcc->buffers, entry) 173462306a36Sopenharmony_ci skb_put_data(skb, &heb->data, heb->len); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci switch (vcc->qos.aal) { 173762306a36Sopenharmony_ci case ATM_AAL0: 173862306a36Sopenharmony_ci /* 2.10.1.5 raw cell receive */ 173962306a36Sopenharmony_ci skb->len = ATM_AAL0_SDU; 174062306a36Sopenharmony_ci skb_set_tail_pointer(skb, skb->len); 174162306a36Sopenharmony_ci break; 174262306a36Sopenharmony_ci case ATM_AAL5: 174362306a36Sopenharmony_ci /* 2.10.1.2 aal5 receive */ 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len); 174662306a36Sopenharmony_ci skb_set_tail_pointer(skb, skb->len); 174762306a36Sopenharmony_ci#ifdef USE_CHECKSUM_HW 174862306a36Sopenharmony_ci if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { 174962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 175062306a36Sopenharmony_ci skb->csum = TCP_CKSUM(skb->data, 175162306a36Sopenharmony_ci he_vcc->pdu_len); 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci#endif 175462306a36Sopenharmony_ci break; 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci#ifdef should_never_happen 175862306a36Sopenharmony_ci if (skb->len > vcc->qos.rxtp.max_sdu) 175962306a36Sopenharmony_ci hprintk("pdu_len (%d) > vcc->qos.rxtp.max_sdu (%d)! cid 0x%x\n", skb->len, vcc->qos.rxtp.max_sdu, cid); 176062306a36Sopenharmony_ci#endif 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci#ifdef notdef 176362306a36Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 176462306a36Sopenharmony_ci#endif 176562306a36Sopenharmony_ci spin_unlock(&he_dev->global_lock); 176662306a36Sopenharmony_ci vcc->push(vcc, skb); 176762306a36Sopenharmony_ci spin_lock(&he_dev->global_lock); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_cireturn_host_buffers: 177262306a36Sopenharmony_ci ++pdus_assembled; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry) 177562306a36Sopenharmony_ci dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 177662306a36Sopenharmony_ci INIT_LIST_HEAD(&he_vcc->buffers); 177762306a36Sopenharmony_ci he_vcc->pdu_len = 0; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cinext_rbrq_entry: 178062306a36Sopenharmony_ci he_dev->rbrq_head = (struct he_rbrq *) 178162306a36Sopenharmony_ci ((unsigned long) he_dev->rbrq_base | 178262306a36Sopenharmony_ci RBRQ_MASK(he_dev->rbrq_head + 1)); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci read_unlock(&vcc_sklist_lock); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (updated) { 178862306a36Sopenharmony_ci if (updated > he_dev->rbrq_peak) 178962306a36Sopenharmony_ci he_dev->rbrq_peak = updated; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head), 179262306a36Sopenharmony_ci G0_RBRQ_H + (group * 16)); 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci return pdus_assembled; 179662306a36Sopenharmony_ci} 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_cistatic void 179962306a36Sopenharmony_cihe_service_tbrq(struct he_dev *he_dev, int group) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci struct he_tbrq *tbrq_tail = (struct he_tbrq *) 180262306a36Sopenharmony_ci ((unsigned long)he_dev->tbrq_base | 180362306a36Sopenharmony_ci he_dev->hsp->group[group].tbrq_tail); 180462306a36Sopenharmony_ci struct he_tpd *tpd; 180562306a36Sopenharmony_ci int slot, updated = 0; 180662306a36Sopenharmony_ci struct he_tpd *__tpd; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci /* 2.1.6 transmit buffer return queue */ 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci while (he_dev->tbrq_head != tbrq_tail) { 181162306a36Sopenharmony_ci ++updated; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci HPRINTK("tbrq%d 0x%x%s%s\n", 181462306a36Sopenharmony_ci group, 181562306a36Sopenharmony_ci TBRQ_TPD(he_dev->tbrq_head), 181662306a36Sopenharmony_ci TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "", 181762306a36Sopenharmony_ci TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); 181862306a36Sopenharmony_ci tpd = NULL; 181962306a36Sopenharmony_ci list_for_each_entry(__tpd, &he_dev->outstanding_tpds, entry) { 182062306a36Sopenharmony_ci if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { 182162306a36Sopenharmony_ci tpd = __tpd; 182262306a36Sopenharmony_ci list_del(&__tpd->entry); 182362306a36Sopenharmony_ci break; 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci if (tpd == NULL) { 182862306a36Sopenharmony_ci hprintk("unable to locate tpd for dma buffer %x\n", 182962306a36Sopenharmony_ci TBRQ_TPD(he_dev->tbrq_head)); 183062306a36Sopenharmony_ci goto next_tbrq_entry; 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (TBRQ_EOS(he_dev->tbrq_head)) { 183462306a36Sopenharmony_ci HPRINTK("wake_up(tx_waitq) cid 0x%x\n", 183562306a36Sopenharmony_ci he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci)); 183662306a36Sopenharmony_ci if (tpd->vcc) 183762306a36Sopenharmony_ci wake_up(&HE_VCC(tpd->vcc)->tx_waitq); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci goto next_tbrq_entry; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci for (slot = 0; slot < TPD_MAXIOV; ++slot) { 184362306a36Sopenharmony_ci if (tpd->iovec[slot].addr) 184462306a36Sopenharmony_ci dma_unmap_single(&he_dev->pci_dev->dev, 184562306a36Sopenharmony_ci tpd->iovec[slot].addr, 184662306a36Sopenharmony_ci tpd->iovec[slot].len & TPD_LEN_MASK, 184762306a36Sopenharmony_ci DMA_TO_DEVICE); 184862306a36Sopenharmony_ci if (tpd->iovec[slot].len & TPD_LST) 184962306a36Sopenharmony_ci break; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (tpd->skb) { /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */ 185462306a36Sopenharmony_ci if (tpd->vcc && tpd->vcc->pop) 185562306a36Sopenharmony_ci tpd->vcc->pop(tpd->vcc, tpd->skb); 185662306a36Sopenharmony_ci else 185762306a36Sopenharmony_ci dev_kfree_skb_any(tpd->skb); 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_cinext_tbrq_entry: 186162306a36Sopenharmony_ci if (tpd) 186262306a36Sopenharmony_ci dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); 186362306a36Sopenharmony_ci he_dev->tbrq_head = (struct he_tbrq *) 186462306a36Sopenharmony_ci ((unsigned long) he_dev->tbrq_base | 186562306a36Sopenharmony_ci TBRQ_MASK(he_dev->tbrq_head + 1)); 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci if (updated) { 186962306a36Sopenharmony_ci if (updated > he_dev->tbrq_peak) 187062306a36Sopenharmony_ci he_dev->tbrq_peak = updated; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head), 187362306a36Sopenharmony_ci G0_TBRQ_H + (group * 16)); 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci} 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cistatic void 187862306a36Sopenharmony_cihe_service_rbpl(struct he_dev *he_dev, int group) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci struct he_rbp *new_tail; 188162306a36Sopenharmony_ci struct he_rbp *rbpl_head; 188262306a36Sopenharmony_ci struct he_buff *heb; 188362306a36Sopenharmony_ci dma_addr_t mapping; 188462306a36Sopenharmony_ci int i; 188562306a36Sopenharmony_ci int moved = 0; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | 188862306a36Sopenharmony_ci RBPL_MASK(he_readl(he_dev, G0_RBPL_S))); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci for (;;) { 189162306a36Sopenharmony_ci new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | 189262306a36Sopenharmony_ci RBPL_MASK(he_dev->rbpl_tail+1)); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci /* table 3.42 -- rbpl_tail should never be set to rbpl_head */ 189562306a36Sopenharmony_ci if (new_tail == rbpl_head) 189662306a36Sopenharmony_ci break; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint); 189962306a36Sopenharmony_ci if (i > (RBPL_TABLE_SIZE - 1)) { 190062306a36Sopenharmony_ci i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE); 190162306a36Sopenharmony_ci if (i > (RBPL_TABLE_SIZE - 1)) 190262306a36Sopenharmony_ci break; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci he_dev->rbpl_hint = i + 1; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC, &mapping); 190762306a36Sopenharmony_ci if (!heb) 190862306a36Sopenharmony_ci break; 190962306a36Sopenharmony_ci heb->mapping = mapping; 191062306a36Sopenharmony_ci list_add(&heb->entry, &he_dev->rbpl_outstanding); 191162306a36Sopenharmony_ci he_dev->rbpl_virt[i] = heb; 191262306a36Sopenharmony_ci set_bit(i, he_dev->rbpl_table); 191362306a36Sopenharmony_ci new_tail->idx = i << RBP_IDX_OFFSET; 191462306a36Sopenharmony_ci new_tail->phys = mapping + offsetof(struct he_buff, data); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci he_dev->rbpl_tail = new_tail; 191762306a36Sopenharmony_ci ++moved; 191862306a36Sopenharmony_ci } 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci if (moved) 192162306a36Sopenharmony_ci he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic void 192562306a36Sopenharmony_cihe_tasklet(unsigned long data) 192662306a36Sopenharmony_ci{ 192762306a36Sopenharmony_ci unsigned long flags; 192862306a36Sopenharmony_ci struct he_dev *he_dev = (struct he_dev *) data; 192962306a36Sopenharmony_ci int group, type; 193062306a36Sopenharmony_ci int updated = 0; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci HPRINTK("tasklet (0x%lx)\n", data); 193362306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci while (he_dev->irq_head != he_dev->irq_tail) { 193662306a36Sopenharmony_ci ++updated; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci type = ITYPE_TYPE(he_dev->irq_head->isw); 193962306a36Sopenharmony_ci group = ITYPE_GROUP(he_dev->irq_head->isw); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci switch (type) { 194262306a36Sopenharmony_ci case ITYPE_RBRQ_THRESH: 194362306a36Sopenharmony_ci HPRINTK("rbrq%d threshold\n", group); 194462306a36Sopenharmony_ci fallthrough; 194562306a36Sopenharmony_ci case ITYPE_RBRQ_TIMER: 194662306a36Sopenharmony_ci if (he_service_rbrq(he_dev, group)) 194762306a36Sopenharmony_ci he_service_rbpl(he_dev, group); 194862306a36Sopenharmony_ci break; 194962306a36Sopenharmony_ci case ITYPE_TBRQ_THRESH: 195062306a36Sopenharmony_ci HPRINTK("tbrq%d threshold\n", group); 195162306a36Sopenharmony_ci fallthrough; 195262306a36Sopenharmony_ci case ITYPE_TPD_COMPLETE: 195362306a36Sopenharmony_ci he_service_tbrq(he_dev, group); 195462306a36Sopenharmony_ci break; 195562306a36Sopenharmony_ci case ITYPE_RBPL_THRESH: 195662306a36Sopenharmony_ci he_service_rbpl(he_dev, group); 195762306a36Sopenharmony_ci break; 195862306a36Sopenharmony_ci case ITYPE_RBPS_THRESH: 195962306a36Sopenharmony_ci /* shouldn't happen unless small buffers enabled */ 196062306a36Sopenharmony_ci break; 196162306a36Sopenharmony_ci case ITYPE_PHY: 196262306a36Sopenharmony_ci HPRINTK("phy interrupt\n"); 196362306a36Sopenharmony_ci#ifdef CONFIG_ATM_HE_USE_SUNI 196462306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 196562306a36Sopenharmony_ci if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt) 196662306a36Sopenharmony_ci he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); 196762306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 196862306a36Sopenharmony_ci#endif 196962306a36Sopenharmony_ci break; 197062306a36Sopenharmony_ci case ITYPE_OTHER: 197162306a36Sopenharmony_ci switch (type|group) { 197262306a36Sopenharmony_ci case ITYPE_PARITY: 197362306a36Sopenharmony_ci hprintk("parity error\n"); 197462306a36Sopenharmony_ci break; 197562306a36Sopenharmony_ci case ITYPE_ABORT: 197662306a36Sopenharmony_ci hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR)); 197762306a36Sopenharmony_ci break; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci break; 198062306a36Sopenharmony_ci case ITYPE_TYPE(ITYPE_INVALID): 198162306a36Sopenharmony_ci /* see 8.1.1 -- check all queues */ 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci HPRINTK("isw not updated 0x%x\n", he_dev->irq_head->isw); 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci he_service_rbrq(he_dev, 0); 198662306a36Sopenharmony_ci he_service_rbpl(he_dev, 0); 198762306a36Sopenharmony_ci he_service_tbrq(he_dev, 0); 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci default: 199062306a36Sopenharmony_ci hprintk("bad isw 0x%x?\n", he_dev->irq_head->isw); 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci he_dev->irq_head->isw = ITYPE_INVALID; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK); 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci if (updated) { 199962306a36Sopenharmony_ci if (updated > he_dev->irq_peak) 200062306a36Sopenharmony_ci he_dev->irq_peak = updated; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci he_writel(he_dev, 200362306a36Sopenharmony_ci IRQ_SIZE(CONFIG_IRQ_SIZE) | 200462306a36Sopenharmony_ci IRQ_THRESH(CONFIG_IRQ_THRESH) | 200562306a36Sopenharmony_ci IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD); 200662306a36Sopenharmony_ci (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata; flush posted writes */ 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 200962306a36Sopenharmony_ci} 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_cistatic irqreturn_t 201262306a36Sopenharmony_cihe_irq_handler(int irq, void *dev_id) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci unsigned long flags; 201562306a36Sopenharmony_ci struct he_dev *he_dev = (struct he_dev * )dev_id; 201662306a36Sopenharmony_ci int handled = 0; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci if (he_dev == NULL) 201962306a36Sopenharmony_ci return IRQ_NONE; 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) | 202462306a36Sopenharmony_ci (*he_dev->irq_tailoffset << 2)); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (he_dev->irq_tail == he_dev->irq_head) { 202762306a36Sopenharmony_ci HPRINTK("tailoffset not updated?\n"); 202862306a36Sopenharmony_ci he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base | 202962306a36Sopenharmony_ci ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2)); 203062306a36Sopenharmony_ci (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ 203162306a36Sopenharmony_ci } 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci#ifdef DEBUG 203462306a36Sopenharmony_ci if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */) 203562306a36Sopenharmony_ci hprintk("spurious (or shared) interrupt?\n"); 203662306a36Sopenharmony_ci#endif 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (he_dev->irq_head != he_dev->irq_tail) { 203962306a36Sopenharmony_ci handled = 1; 204062306a36Sopenharmony_ci tasklet_schedule(&he_dev->tasklet); 204162306a36Sopenharmony_ci he_writel(he_dev, INT_CLEAR_A, INT_FIFO); /* clear interrupt */ 204262306a36Sopenharmony_ci (void) he_readl(he_dev, INT_FIFO); /* flush posted writes */ 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 204562306a36Sopenharmony_ci return IRQ_RETVAL(handled); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci} 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_cistatic __inline__ void 205062306a36Sopenharmony_ci__enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) 205162306a36Sopenharmony_ci{ 205262306a36Sopenharmony_ci struct he_tpdrq *new_tail; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci HPRINTK("tpdrq %p cid 0x%x -> tpdrq_tail %p\n", 205562306a36Sopenharmony_ci tpd, cid, he_dev->tpdrq_tail); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* new_tail = he_dev->tpdrq_tail; */ 205862306a36Sopenharmony_ci new_tail = (struct he_tpdrq *) ((unsigned long) he_dev->tpdrq_base | 205962306a36Sopenharmony_ci TPDRQ_MASK(he_dev->tpdrq_tail+1)); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci /* 206262306a36Sopenharmony_ci * check to see if we are about to set the tail == head 206362306a36Sopenharmony_ci * if true, update the head pointer from the adapter 206462306a36Sopenharmony_ci * to see if this is really the case (reading the queue 206562306a36Sopenharmony_ci * head for every enqueue would be unnecessarily slow) 206662306a36Sopenharmony_ci */ 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (new_tail == he_dev->tpdrq_head) { 206962306a36Sopenharmony_ci he_dev->tpdrq_head = (struct he_tpdrq *) 207062306a36Sopenharmony_ci (((unsigned long)he_dev->tpdrq_base) | 207162306a36Sopenharmony_ci TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H))); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci if (new_tail == he_dev->tpdrq_head) { 207462306a36Sopenharmony_ci int slot; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci hprintk("tpdrq full (cid 0x%x)\n", cid); 207762306a36Sopenharmony_ci /* 207862306a36Sopenharmony_ci * FIXME 207962306a36Sopenharmony_ci * push tpd onto a transmit backlog queue 208062306a36Sopenharmony_ci * after service_tbrq, service the backlog 208162306a36Sopenharmony_ci * for now, we just drop the pdu 208262306a36Sopenharmony_ci */ 208362306a36Sopenharmony_ci for (slot = 0; slot < TPD_MAXIOV; ++slot) { 208462306a36Sopenharmony_ci if (tpd->iovec[slot].addr) 208562306a36Sopenharmony_ci dma_unmap_single(&he_dev->pci_dev->dev, 208662306a36Sopenharmony_ci tpd->iovec[slot].addr, 208762306a36Sopenharmony_ci tpd->iovec[slot].len & TPD_LEN_MASK, 208862306a36Sopenharmony_ci DMA_TO_DEVICE); 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci if (tpd->skb) { 209162306a36Sopenharmony_ci if (tpd->vcc->pop) 209262306a36Sopenharmony_ci tpd->vcc->pop(tpd->vcc, tpd->skb); 209362306a36Sopenharmony_ci else 209462306a36Sopenharmony_ci dev_kfree_skb_any(tpd->skb); 209562306a36Sopenharmony_ci atomic_inc(&tpd->vcc->stats->tx_err); 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); 209862306a36Sopenharmony_ci return; 209962306a36Sopenharmony_ci } 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* 2.1.5 transmit packet descriptor ready queue */ 210362306a36Sopenharmony_ci list_add_tail(&tpd->entry, &he_dev->outstanding_tpds); 210462306a36Sopenharmony_ci he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status); 210562306a36Sopenharmony_ci he_dev->tpdrq_tail->cid = cid; 210662306a36Sopenharmony_ci wmb(); 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci he_dev->tpdrq_tail = new_tail; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci he_writel(he_dev, TPDRQ_MASK(he_dev->tpdrq_tail), TPDRQ_T); 211162306a36Sopenharmony_ci (void) he_readl(he_dev, TPDRQ_T); /* flush posted writes */ 211262306a36Sopenharmony_ci} 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_cistatic int 211562306a36Sopenharmony_cihe_open(struct atm_vcc *vcc) 211662306a36Sopenharmony_ci{ 211762306a36Sopenharmony_ci unsigned long flags; 211862306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(vcc->dev); 211962306a36Sopenharmony_ci struct he_vcc *he_vcc; 212062306a36Sopenharmony_ci int err = 0; 212162306a36Sopenharmony_ci unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock; 212262306a36Sopenharmony_ci short vpi = vcc->vpi; 212362306a36Sopenharmony_ci int vci = vcc->vci; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) 212662306a36Sopenharmony_ci return 0; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci HPRINTK("open vcc %p %d.%d\n", vcc, vpi, vci); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci set_bit(ATM_VF_ADDR, &vcc->flags); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci cid = he_mkcid(he_dev, vpi, vci); 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci he_vcc = kmalloc(sizeof(struct he_vcc), GFP_ATOMIC); 213562306a36Sopenharmony_ci if (he_vcc == NULL) { 213662306a36Sopenharmony_ci hprintk("unable to allocate he_vcc during open\n"); 213762306a36Sopenharmony_ci return -ENOMEM; 213862306a36Sopenharmony_ci } 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci INIT_LIST_HEAD(&he_vcc->buffers); 214162306a36Sopenharmony_ci he_vcc->pdu_len = 0; 214262306a36Sopenharmony_ci he_vcc->rc_index = -1; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci init_waitqueue_head(&he_vcc->rx_waitq); 214562306a36Sopenharmony_ci init_waitqueue_head(&he_vcc->tx_waitq); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci vcc->dev_data = he_vcc; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 215062306a36Sopenharmony_ci int pcr_goal; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci pcr_goal = atm_pcr_goal(&vcc->qos.txtp); 215362306a36Sopenharmony_ci if (pcr_goal == 0) 215462306a36Sopenharmony_ci pcr_goal = he_dev->atm_dev->link_rate; 215562306a36Sopenharmony_ci if (pcr_goal < 0) /* means round down, technically */ 215662306a36Sopenharmony_ci pcr_goal = -pcr_goal; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci switch (vcc->qos.aal) { 216162306a36Sopenharmony_ci case ATM_AAL5: 216262306a36Sopenharmony_ci tsr0_aal = TSR0_AAL5; 216362306a36Sopenharmony_ci tsr4 = TSR4_AAL5; 216462306a36Sopenharmony_ci break; 216562306a36Sopenharmony_ci case ATM_AAL0: 216662306a36Sopenharmony_ci tsr0_aal = TSR0_AAL0_SDU; 216762306a36Sopenharmony_ci tsr4 = TSR4_AAL0_SDU; 216862306a36Sopenharmony_ci break; 216962306a36Sopenharmony_ci default: 217062306a36Sopenharmony_ci err = -EINVAL; 217162306a36Sopenharmony_ci goto open_failed; 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 217562306a36Sopenharmony_ci tsr0 = he_readl_tsr0(he_dev, cid); 217662306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci if (TSR0_CONN_STATE(tsr0) != 0) { 217962306a36Sopenharmony_ci hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0); 218062306a36Sopenharmony_ci err = -EBUSY; 218162306a36Sopenharmony_ci goto open_failed; 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci switch (vcc->qos.txtp.traffic_class) { 218562306a36Sopenharmony_ci case ATM_UBR: 218662306a36Sopenharmony_ci /* 2.3.3.1 open connection ubr */ 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci tsr0 = TSR0_UBR | TSR0_GROUP(0) | tsr0_aal | 218962306a36Sopenharmony_ci TSR0_USE_WMIN | TSR0_UPDATE_GER; 219062306a36Sopenharmony_ci break; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci case ATM_CBR: 219362306a36Sopenharmony_ci /* 2.3.3.2 open connection cbr */ 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci /* 8.2.3 cbr scheduler wrap problem -- limit to 90% total link rate */ 219662306a36Sopenharmony_ci if ((he_dev->total_bw + pcr_goal) 219762306a36Sopenharmony_ci > (he_dev->atm_dev->link_rate * 9 / 10)) 219862306a36Sopenharmony_ci { 219962306a36Sopenharmony_ci err = -EBUSY; 220062306a36Sopenharmony_ci goto open_failed; 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); /* also protects he_dev->cs_stper[] */ 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci /* find an unused cs_stper register */ 220662306a36Sopenharmony_ci for (reg = 0; reg < HE_NUM_CS_STPER; ++reg) 220762306a36Sopenharmony_ci if (he_dev->cs_stper[reg].inuse == 0 || 220862306a36Sopenharmony_ci he_dev->cs_stper[reg].pcr == pcr_goal) 220962306a36Sopenharmony_ci break; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci if (reg == HE_NUM_CS_STPER) { 221262306a36Sopenharmony_ci err = -EBUSY; 221362306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 221462306a36Sopenharmony_ci goto open_failed; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci he_dev->total_bw += pcr_goal; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci he_vcc->rc_index = reg; 222062306a36Sopenharmony_ci ++he_dev->cs_stper[reg].inuse; 222162306a36Sopenharmony_ci he_dev->cs_stper[reg].pcr = pcr_goal; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci clock = he_is622(he_dev) ? 66667000 : 50000000; 222462306a36Sopenharmony_ci period = clock / pcr_goal; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci HPRINTK("rc_index = %d period = %d\n", 222762306a36Sopenharmony_ci reg, period); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci he_writel_mbox(he_dev, rate_to_atmf(period/2), 223062306a36Sopenharmony_ci CS_STPER0 + reg); 223162306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal | 223462306a36Sopenharmony_ci TSR0_RC_INDEX(reg); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci break; 223762306a36Sopenharmony_ci default: 223862306a36Sopenharmony_ci err = -EINVAL; 223962306a36Sopenharmony_ci goto open_failed; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci he_writel_tsr0(he_dev, tsr0, cid); 224562306a36Sopenharmony_ci he_writel_tsr4(he_dev, tsr4 | 1, cid); 224662306a36Sopenharmony_ci he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(0)) | 224762306a36Sopenharmony_ci TSR1_PCR(rate_to_atmf(pcr_goal)), cid); 224862306a36Sopenharmony_ci he_writel_tsr2(he_dev, TSR2_ACR(rate_to_atmf(pcr_goal)), cid); 224962306a36Sopenharmony_ci he_writel_tsr9(he_dev, TSR9_OPEN_CONN, cid); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci he_writel_tsr3(he_dev, 0x0, cid); 225262306a36Sopenharmony_ci he_writel_tsr5(he_dev, 0x0, cid); 225362306a36Sopenharmony_ci he_writel_tsr6(he_dev, 0x0, cid); 225462306a36Sopenharmony_ci he_writel_tsr7(he_dev, 0x0, cid); 225562306a36Sopenharmony_ci he_writel_tsr8(he_dev, 0x0, cid); 225662306a36Sopenharmony_ci he_writel_tsr10(he_dev, 0x0, cid); 225762306a36Sopenharmony_ci he_writel_tsr11(he_dev, 0x0, cid); 225862306a36Sopenharmony_ci he_writel_tsr12(he_dev, 0x0, cid); 225962306a36Sopenharmony_ci he_writel_tsr13(he_dev, 0x0, cid); 226062306a36Sopenharmony_ci he_writel_tsr14(he_dev, 0x0, cid); 226162306a36Sopenharmony_ci (void) he_readl_tsr0(he_dev, cid); /* flush posted writes */ 226262306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 226362306a36Sopenharmony_ci } 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE) { 226662306a36Sopenharmony_ci unsigned aal; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid, 226962306a36Sopenharmony_ci &HE_VCC(vcc)->rx_waitq); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci switch (vcc->qos.aal) { 227262306a36Sopenharmony_ci case ATM_AAL5: 227362306a36Sopenharmony_ci aal = RSR0_AAL5; 227462306a36Sopenharmony_ci break; 227562306a36Sopenharmony_ci case ATM_AAL0: 227662306a36Sopenharmony_ci aal = RSR0_RAWCELL; 227762306a36Sopenharmony_ci break; 227862306a36Sopenharmony_ci default: 227962306a36Sopenharmony_ci err = -EINVAL; 228062306a36Sopenharmony_ci goto open_failed; 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci rsr0 = he_readl_rsr0(he_dev, cid); 228662306a36Sopenharmony_ci if (rsr0 & RSR0_OPEN_CONN) { 228762306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0); 229062306a36Sopenharmony_ci err = -EBUSY; 229162306a36Sopenharmony_ci goto open_failed; 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci rsr1 = RSR1_GROUP(0) | RSR1_RBPL_ONLY; 229562306a36Sopenharmony_ci rsr4 = RSR4_GROUP(0) | RSR4_RBPL_ONLY; 229662306a36Sopenharmony_ci rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? 229762306a36Sopenharmony_ci (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci#ifdef USE_CHECKSUM_HW 230062306a36Sopenharmony_ci if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) 230162306a36Sopenharmony_ci rsr0 |= RSR0_TCP_CKSUM; 230262306a36Sopenharmony_ci#endif 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci he_writel_rsr4(he_dev, rsr4, cid); 230562306a36Sopenharmony_ci he_writel_rsr1(he_dev, rsr1, cid); 230662306a36Sopenharmony_ci /* 5.1.11 last parameter initialized should be 230762306a36Sopenharmony_ci the open/closed indication in rsr0 */ 230862306a36Sopenharmony_ci he_writel_rsr0(he_dev, 230962306a36Sopenharmony_ci rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid); 231062306a36Sopenharmony_ci (void) he_readl_rsr0(he_dev, cid); /* flush posted writes */ 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ciopen_failed: 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci if (err) { 231862306a36Sopenharmony_ci kfree(he_vcc); 231962306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 232062306a36Sopenharmony_ci } 232162306a36Sopenharmony_ci else 232262306a36Sopenharmony_ci set_bit(ATM_VF_READY, &vcc->flags); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci return err; 232562306a36Sopenharmony_ci} 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_cistatic void 232862306a36Sopenharmony_cihe_close(struct atm_vcc *vcc) 232962306a36Sopenharmony_ci{ 233062306a36Sopenharmony_ci unsigned long flags; 233162306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 233262306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(vcc->dev); 233362306a36Sopenharmony_ci struct he_tpd *tpd; 233462306a36Sopenharmony_ci unsigned cid; 233562306a36Sopenharmony_ci struct he_vcc *he_vcc = HE_VCC(vcc); 233662306a36Sopenharmony_ci#define MAX_RETRY 30 233762306a36Sopenharmony_ci int retry = 0, sleep = 1, tx_inuse; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci HPRINTK("close vcc %p %d.%d\n", vcc, vcc->vpi, vcc->vci); 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci clear_bit(ATM_VF_READY, &vcc->flags); 234262306a36Sopenharmony_ci cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE) { 234562306a36Sopenharmony_ci int timeout; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci HPRINTK("close rx cid 0x%x\n", cid); 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci /* 2.7.2.2 close receive operation */ 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci /* wait for previous close (if any) to finish */ 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 235462306a36Sopenharmony_ci while (he_readl(he_dev, RCC_STAT) & RCC_BUSY) { 235562306a36Sopenharmony_ci HPRINTK("close cid 0x%x RCC_BUSY\n", cid); 235662306a36Sopenharmony_ci udelay(250); 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 236062306a36Sopenharmony_ci add_wait_queue(&he_vcc->rx_waitq, &wait); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci he_writel_rsr0(he_dev, RSR0_CLOSE_CONN, cid); 236362306a36Sopenharmony_ci (void) he_readl_rsr0(he_dev, cid); /* flush posted writes */ 236462306a36Sopenharmony_ci he_writel_mbox(he_dev, cid, RXCON_CLOSE); 236562306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci timeout = schedule_timeout(30*HZ); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci remove_wait_queue(&he_vcc->rx_waitq, &wait); 237062306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci if (timeout == 0) 237362306a36Sopenharmony_ci hprintk("close rx timeout cid 0x%x\n", cid); 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci HPRINTK("close rx cid 0x%x complete\n", cid); 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 238062306a36Sopenharmony_ci volatile unsigned tsr4, tsr0; 238162306a36Sopenharmony_ci int timeout; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci HPRINTK("close tx cid 0x%x\n", cid); 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci /* 2.1.2 238662306a36Sopenharmony_ci * 238762306a36Sopenharmony_ci * ... the host must first stop queueing packets to the TPDRQ 238862306a36Sopenharmony_ci * on the connection to be closed, then wait for all outstanding 238962306a36Sopenharmony_ci * packets to be transmitted and their buffers returned to the 239062306a36Sopenharmony_ci * TBRQ. When the last packet on the connection arrives in the 239162306a36Sopenharmony_ci * TBRQ, the host issues the close command to the adapter. 239262306a36Sopenharmony_ci */ 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci while (((tx_inuse = refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) && 239562306a36Sopenharmony_ci (retry < MAX_RETRY)) { 239662306a36Sopenharmony_ci msleep(sleep); 239762306a36Sopenharmony_ci if (sleep < 250) 239862306a36Sopenharmony_ci sleep = sleep * 2; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci ++retry; 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci if (tx_inuse > 1) 240462306a36Sopenharmony_ci hprintk("close tx cid 0x%x tx_inuse = %d\n", cid, tx_inuse); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci /* 2.3.1.1 generic close operations with flush */ 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 240962306a36Sopenharmony_ci he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid); 241062306a36Sopenharmony_ci /* also clears TSR4_SESSION_ENDED */ 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci switch (vcc->qos.txtp.traffic_class) { 241362306a36Sopenharmony_ci case ATM_UBR: 241462306a36Sopenharmony_ci he_writel_tsr1(he_dev, 241562306a36Sopenharmony_ci TSR1_MCR(rate_to_atmf(200000)) 241662306a36Sopenharmony_ci | TSR1_PCR(0), cid); 241762306a36Sopenharmony_ci break; 241862306a36Sopenharmony_ci case ATM_CBR: 241962306a36Sopenharmony_ci he_writel_tsr14_upper(he_dev, TSR14_DELETE, cid); 242062306a36Sopenharmony_ci break; 242162306a36Sopenharmony_ci } 242262306a36Sopenharmony_ci (void) he_readl_tsr4(he_dev, cid); /* flush posted writes */ 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci tpd = __alloc_tpd(he_dev); 242562306a36Sopenharmony_ci if (tpd == NULL) { 242662306a36Sopenharmony_ci hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid); 242762306a36Sopenharmony_ci goto close_tx_incomplete; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci tpd->status |= TPD_EOS | TPD_INT; 243062306a36Sopenharmony_ci tpd->skb = NULL; 243162306a36Sopenharmony_ci tpd->vcc = vcc; 243262306a36Sopenharmony_ci wmb(); 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 243562306a36Sopenharmony_ci add_wait_queue(&he_vcc->tx_waitq, &wait); 243662306a36Sopenharmony_ci __enqueue_tpd(he_dev, tpd, cid); 243762306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci timeout = schedule_timeout(30*HZ); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci remove_wait_queue(&he_vcc->tx_waitq, &wait); 244262306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci if (timeout == 0) { 244762306a36Sopenharmony_ci hprintk("close tx timeout cid 0x%x\n", cid); 244862306a36Sopenharmony_ci goto close_tx_incomplete; 244962306a36Sopenharmony_ci } 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { 245262306a36Sopenharmony_ci HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); 245362306a36Sopenharmony_ci udelay(250); 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0) { 245762306a36Sopenharmony_ci HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0); 245862306a36Sopenharmony_ci udelay(250); 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ciclose_tx_incomplete: 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 246462306a36Sopenharmony_ci int reg = he_vcc->rc_index; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci HPRINTK("cs_stper reg = %d\n", reg); 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci if (he_dev->cs_stper[reg].inuse == 0) 246962306a36Sopenharmony_ci hprintk("cs_stper[%d].inuse = 0!\n", reg); 247062306a36Sopenharmony_ci else 247162306a36Sopenharmony_ci --he_dev->cs_stper[reg].inuse; 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci he_dev->total_bw -= he_dev->cs_stper[reg].pcr; 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci HPRINTK("close tx cid 0x%x complete\n", cid); 247862306a36Sopenharmony_ci } 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci kfree(he_vcc); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 248362306a36Sopenharmony_ci} 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_cistatic int 248662306a36Sopenharmony_cihe_send(struct atm_vcc *vcc, struct sk_buff *skb) 248762306a36Sopenharmony_ci{ 248862306a36Sopenharmony_ci unsigned long flags; 248962306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(vcc->dev); 249062306a36Sopenharmony_ci unsigned cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); 249162306a36Sopenharmony_ci struct he_tpd *tpd; 249262306a36Sopenharmony_ci#ifdef USE_SCATTERGATHER 249362306a36Sopenharmony_ci int i, slot = 0; 249462306a36Sopenharmony_ci#endif 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci#define HE_TPD_BUFSIZE 0xffff 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci); 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci if ((skb->len > HE_TPD_BUFSIZE) || 250162306a36Sopenharmony_ci ((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU))) { 250262306a36Sopenharmony_ci hprintk("buffer too large (or small) -- %d bytes\n", skb->len ); 250362306a36Sopenharmony_ci if (vcc->pop) 250462306a36Sopenharmony_ci vcc->pop(vcc, skb); 250562306a36Sopenharmony_ci else 250662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 250762306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 250862306a36Sopenharmony_ci return -EINVAL; 250962306a36Sopenharmony_ci } 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci#ifndef USE_SCATTERGATHER 251262306a36Sopenharmony_ci if (skb_shinfo(skb)->nr_frags) { 251362306a36Sopenharmony_ci hprintk("no scatter/gather support\n"); 251462306a36Sopenharmony_ci if (vcc->pop) 251562306a36Sopenharmony_ci vcc->pop(vcc, skb); 251662306a36Sopenharmony_ci else 251762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 251862306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 251962306a36Sopenharmony_ci return -EINVAL; 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci#endif 252262306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci tpd = __alloc_tpd(he_dev); 252562306a36Sopenharmony_ci if (tpd == NULL) { 252662306a36Sopenharmony_ci if (vcc->pop) 252762306a36Sopenharmony_ci vcc->pop(vcc, skb); 252862306a36Sopenharmony_ci else 252962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 253062306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 253162306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 253262306a36Sopenharmony_ci return -ENOMEM; 253362306a36Sopenharmony_ci } 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci if (vcc->qos.aal == ATM_AAL5) 253662306a36Sopenharmony_ci tpd->status |= TPD_CELLTYPE(TPD_USERCELL); 253762306a36Sopenharmony_ci else { 253862306a36Sopenharmony_ci char *pti_clp = (void *) (skb->data + 3); 253962306a36Sopenharmony_ci int clp, pti; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci pti = (*pti_clp & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; 254262306a36Sopenharmony_ci clp = (*pti_clp & ATM_HDR_CLP); 254362306a36Sopenharmony_ci tpd->status |= TPD_CELLTYPE(pti); 254462306a36Sopenharmony_ci if (clp) 254562306a36Sopenharmony_ci tpd->status |= TPD_CLP; 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD); 254862306a36Sopenharmony_ci } 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci#ifdef USE_SCATTERGATHER 255162306a36Sopenharmony_ci tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev, skb->data, 255262306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 255362306a36Sopenharmony_ci tpd->iovec[slot].len = skb_headlen(skb); 255462306a36Sopenharmony_ci ++slot; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 255762306a36Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci if (slot == TPD_MAXIOV) { /* queue tpd; start new tpd */ 256062306a36Sopenharmony_ci tpd->vcc = vcc; 256162306a36Sopenharmony_ci tpd->skb = NULL; /* not the last fragment 256262306a36Sopenharmony_ci so dont ->push() yet */ 256362306a36Sopenharmony_ci wmb(); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci __enqueue_tpd(he_dev, tpd, cid); 256662306a36Sopenharmony_ci tpd = __alloc_tpd(he_dev); 256762306a36Sopenharmony_ci if (tpd == NULL) { 256862306a36Sopenharmony_ci if (vcc->pop) 256962306a36Sopenharmony_ci vcc->pop(vcc, skb); 257062306a36Sopenharmony_ci else 257162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 257262306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 257362306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 257462306a36Sopenharmony_ci return -ENOMEM; 257562306a36Sopenharmony_ci } 257662306a36Sopenharmony_ci tpd->status |= TPD_USERCELL; 257762306a36Sopenharmony_ci slot = 0; 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci tpd->iovec[slot].addr = skb_frag_dma_map(&he_dev->pci_dev->dev, 258162306a36Sopenharmony_ci frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); 258262306a36Sopenharmony_ci tpd->iovec[slot].len = skb_frag_size(frag); 258362306a36Sopenharmony_ci ++slot; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci tpd->iovec[slot - 1].len |= TPD_LST; 258862306a36Sopenharmony_ci#else 258962306a36Sopenharmony_ci tpd->address0 = dma_map_single(&he_dev->pci_dev->dev, skb->data, skb->len, DMA_TO_DEVICE); 259062306a36Sopenharmony_ci tpd->length0 = skb->len | TPD_LST; 259162306a36Sopenharmony_ci#endif 259262306a36Sopenharmony_ci tpd->status |= TPD_INT; 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci tpd->vcc = vcc; 259562306a36Sopenharmony_ci tpd->skb = skb; 259662306a36Sopenharmony_ci wmb(); 259762306a36Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci __enqueue_tpd(he_dev, tpd, cid); 260062306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx); 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci return 0; 260562306a36Sopenharmony_ci} 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_cistatic int 260862306a36Sopenharmony_cihe_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg) 260962306a36Sopenharmony_ci{ 261062306a36Sopenharmony_ci unsigned long flags; 261162306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(atm_dev); 261262306a36Sopenharmony_ci struct he_ioctl_reg reg; 261362306a36Sopenharmony_ci int err = 0; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci switch (cmd) { 261662306a36Sopenharmony_ci case HE_GET_REG: 261762306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 261862306a36Sopenharmony_ci return -EPERM; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci if (copy_from_user(®, arg, 262162306a36Sopenharmony_ci sizeof(struct he_ioctl_reg))) 262262306a36Sopenharmony_ci return -EFAULT; 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 262562306a36Sopenharmony_ci switch (reg.type) { 262662306a36Sopenharmony_ci case HE_REGTYPE_PCI: 262762306a36Sopenharmony_ci if (reg.addr >= HE_REGMAP_SIZE) { 262862306a36Sopenharmony_ci err = -EINVAL; 262962306a36Sopenharmony_ci break; 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci reg.val = he_readl(he_dev, reg.addr); 263362306a36Sopenharmony_ci break; 263462306a36Sopenharmony_ci case HE_REGTYPE_RCM: 263562306a36Sopenharmony_ci reg.val = 263662306a36Sopenharmony_ci he_readl_rcm(he_dev, reg.addr); 263762306a36Sopenharmony_ci break; 263862306a36Sopenharmony_ci case HE_REGTYPE_TCM: 263962306a36Sopenharmony_ci reg.val = 264062306a36Sopenharmony_ci he_readl_tcm(he_dev, reg.addr); 264162306a36Sopenharmony_ci break; 264262306a36Sopenharmony_ci case HE_REGTYPE_MBOX: 264362306a36Sopenharmony_ci reg.val = 264462306a36Sopenharmony_ci he_readl_mbox(he_dev, reg.addr); 264562306a36Sopenharmony_ci break; 264662306a36Sopenharmony_ci default: 264762306a36Sopenharmony_ci err = -EINVAL; 264862306a36Sopenharmony_ci break; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 265162306a36Sopenharmony_ci if (err == 0) 265262306a36Sopenharmony_ci if (copy_to_user(arg, ®, 265362306a36Sopenharmony_ci sizeof(struct he_ioctl_reg))) 265462306a36Sopenharmony_ci return -EFAULT; 265562306a36Sopenharmony_ci break; 265662306a36Sopenharmony_ci default: 265762306a36Sopenharmony_ci#ifdef CONFIG_ATM_HE_USE_SUNI 265862306a36Sopenharmony_ci if (atm_dev->phy && atm_dev->phy->ioctl) 265962306a36Sopenharmony_ci err = atm_dev->phy->ioctl(atm_dev, cmd, arg); 266062306a36Sopenharmony_ci#else /* CONFIG_ATM_HE_USE_SUNI */ 266162306a36Sopenharmony_ci err = -EINVAL; 266262306a36Sopenharmony_ci#endif /* CONFIG_ATM_HE_USE_SUNI */ 266362306a36Sopenharmony_ci break; 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci return err; 266762306a36Sopenharmony_ci} 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_cistatic void 267062306a36Sopenharmony_cihe_phy_put(struct atm_dev *atm_dev, unsigned char val, unsigned long addr) 267162306a36Sopenharmony_ci{ 267262306a36Sopenharmony_ci unsigned long flags; 267362306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(atm_dev); 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr); 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 267862306a36Sopenharmony_ci he_writel(he_dev, val, FRAMER + (addr*4)); 267962306a36Sopenharmony_ci (void) he_readl(he_dev, FRAMER + (addr*4)); /* flush posted writes */ 268062306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 268162306a36Sopenharmony_ci} 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_cistatic unsigned char 268562306a36Sopenharmony_cihe_phy_get(struct atm_dev *atm_dev, unsigned long addr) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci unsigned long flags; 268862306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(atm_dev); 268962306a36Sopenharmony_ci unsigned reg; 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 269262306a36Sopenharmony_ci reg = he_readl(he_dev, FRAMER + (addr*4)); 269362306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg); 269662306a36Sopenharmony_ci return reg; 269762306a36Sopenharmony_ci} 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_cistatic int 270062306a36Sopenharmony_cihe_proc_read(struct atm_dev *dev, loff_t *pos, char *page) 270162306a36Sopenharmony_ci{ 270262306a36Sopenharmony_ci unsigned long flags; 270362306a36Sopenharmony_ci struct he_dev *he_dev = HE_DEV(dev); 270462306a36Sopenharmony_ci int left, i; 270562306a36Sopenharmony_ci#ifdef notdef 270662306a36Sopenharmony_ci struct he_rbrq *rbrq_tail; 270762306a36Sopenharmony_ci struct he_tpdrq *tpdrq_head; 270862306a36Sopenharmony_ci int rbpl_head, rbpl_tail; 270962306a36Sopenharmony_ci#endif 271062306a36Sopenharmony_ci static long mcc = 0, oec = 0, dcc = 0, cec = 0; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci left = *pos; 271462306a36Sopenharmony_ci if (!left--) 271562306a36Sopenharmony_ci return sprintf(page, "ATM he driver\n"); 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci if (!left--) 271862306a36Sopenharmony_ci return sprintf(page, "%s%s\n\n", 271962306a36Sopenharmony_ci he_dev->prod_id, he_dev->media & 0x40 ? "SM" : "MM"); 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (!left--) 272262306a36Sopenharmony_ci return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n"); 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci spin_lock_irqsave(&he_dev->global_lock, flags); 272562306a36Sopenharmony_ci mcc += he_readl(he_dev, MCC); 272662306a36Sopenharmony_ci oec += he_readl(he_dev, OEC); 272762306a36Sopenharmony_ci dcc += he_readl(he_dev, DCC); 272862306a36Sopenharmony_ci cec += he_readl(he_dev, CEC); 272962306a36Sopenharmony_ci spin_unlock_irqrestore(&he_dev->global_lock, flags); 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci if (!left--) 273262306a36Sopenharmony_ci return sprintf(page, "%16ld %16ld %13ld %17ld\n\n", 273362306a36Sopenharmony_ci mcc, oec, dcc, cec); 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci if (!left--) 273662306a36Sopenharmony_ci return sprintf(page, "irq_size = %d inuse = ? peak = %d\n", 273762306a36Sopenharmony_ci CONFIG_IRQ_SIZE, he_dev->irq_peak); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci if (!left--) 274062306a36Sopenharmony_ci return sprintf(page, "tpdrq_size = %d inuse = ?\n", 274162306a36Sopenharmony_ci CONFIG_TPDRQ_SIZE); 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci if (!left--) 274462306a36Sopenharmony_ci return sprintf(page, "rbrq_size = %d inuse = ? peak = %d\n", 274562306a36Sopenharmony_ci CONFIG_RBRQ_SIZE, he_dev->rbrq_peak); 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci if (!left--) 274862306a36Sopenharmony_ci return sprintf(page, "tbrq_size = %d peak = %d\n", 274962306a36Sopenharmony_ci CONFIG_TBRQ_SIZE, he_dev->tbrq_peak); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci#ifdef notdef 275362306a36Sopenharmony_ci rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); 275462306a36Sopenharmony_ci rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci inuse = rbpl_head - rbpl_tail; 275762306a36Sopenharmony_ci if (inuse < 0) 275862306a36Sopenharmony_ci inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp); 275962306a36Sopenharmony_ci inuse /= sizeof(struct he_rbp); 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci if (!left--) 276262306a36Sopenharmony_ci return sprintf(page, "rbpl_size = %d inuse = %d\n\n", 276362306a36Sopenharmony_ci CONFIG_RBPL_SIZE, inuse); 276462306a36Sopenharmony_ci#endif 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci if (!left--) 276762306a36Sopenharmony_ci return sprintf(page, "rate controller periods (cbr)\n pcr #vc\n"); 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci for (i = 0; i < HE_NUM_CS_STPER; ++i) 277062306a36Sopenharmony_ci if (!left--) 277162306a36Sopenharmony_ci return sprintf(page, "cs_stper%-2d %8ld %3d\n", i, 277262306a36Sopenharmony_ci he_dev->cs_stper[i].pcr, 277362306a36Sopenharmony_ci he_dev->cs_stper[i].inuse); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci if (!left--) 277662306a36Sopenharmony_ci return sprintf(page, "total bw (cbr): %d (limit %d)\n", 277762306a36Sopenharmony_ci he_dev->total_bw, he_dev->atm_dev->link_rate * 10 / 9); 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci return 0; 278062306a36Sopenharmony_ci} 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci/* eeprom routines -- see 4.7 */ 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_cistatic u8 read_prom_byte(struct he_dev *he_dev, int addr) 278562306a36Sopenharmony_ci{ 278662306a36Sopenharmony_ci u32 val = 0, tmp_read = 0; 278762306a36Sopenharmony_ci int i, j = 0; 278862306a36Sopenharmony_ci u8 byte_read = 0; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci val = readl(he_dev->membase + HOST_CNTL); 279162306a36Sopenharmony_ci val &= 0xFFFFE0FF; 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci /* Turn on write enable */ 279462306a36Sopenharmony_ci val |= 0x800; 279562306a36Sopenharmony_ci he_writel(he_dev, val, HOST_CNTL); 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci /* Send READ instruction */ 279862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(readtab); i++) { 279962306a36Sopenharmony_ci he_writel(he_dev, val | readtab[i], HOST_CNTL); 280062306a36Sopenharmony_ci udelay(EEPROM_DELAY); 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci /* Next, we need to send the byte address to read from */ 280462306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 280562306a36Sopenharmony_ci he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); 280662306a36Sopenharmony_ci udelay(EEPROM_DELAY); 280762306a36Sopenharmony_ci he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); 280862306a36Sopenharmony_ci udelay(EEPROM_DELAY); 280962306a36Sopenharmony_ci } 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci j = 0; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci val &= 0xFFFFF7FF; /* Turn off write enable */ 281462306a36Sopenharmony_ci he_writel(he_dev, val, HOST_CNTL); 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci /* Now, we can read data from the EEPROM by clocking it in */ 281762306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 281862306a36Sopenharmony_ci he_writel(he_dev, val | clocktab[j++], HOST_CNTL); 281962306a36Sopenharmony_ci udelay(EEPROM_DELAY); 282062306a36Sopenharmony_ci tmp_read = he_readl(he_dev, HOST_CNTL); 282162306a36Sopenharmony_ci byte_read |= (unsigned char) 282262306a36Sopenharmony_ci ((tmp_read & ID_DOUT) >> ID_DOFFSET << i); 282362306a36Sopenharmony_ci he_writel(he_dev, val | clocktab[j++], HOST_CNTL); 282462306a36Sopenharmony_ci udelay(EEPROM_DELAY); 282562306a36Sopenharmony_ci } 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci he_writel(he_dev, val | ID_CS, HOST_CNTL); 282862306a36Sopenharmony_ci udelay(EEPROM_DELAY); 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci return byte_read; 283162306a36Sopenharmony_ci} 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 283462306a36Sopenharmony_ciMODULE_AUTHOR("chas williams <chas@cmf.nrl.navy.mil>"); 283562306a36Sopenharmony_ciMODULE_DESCRIPTION("ForeRunnerHE ATM Adapter driver"); 283662306a36Sopenharmony_cimodule_param(disable64, bool, 0); 283762306a36Sopenharmony_ciMODULE_PARM_DESC(disable64, "disable 64-bit pci bus transfers"); 283862306a36Sopenharmony_cimodule_param(nvpibits, short, 0); 283962306a36Sopenharmony_ciMODULE_PARM_DESC(nvpibits, "numbers of bits for vpi (default 0)"); 284062306a36Sopenharmony_cimodule_param(nvcibits, short, 0); 284162306a36Sopenharmony_ciMODULE_PARM_DESC(nvcibits, "numbers of bits for vci (default 12)"); 284262306a36Sopenharmony_cimodule_param(rx_skb_reserve, short, 0); 284362306a36Sopenharmony_ciMODULE_PARM_DESC(rx_skb_reserve, "padding for receive skb (default 16)"); 284462306a36Sopenharmony_cimodule_param(irq_coalesce, bool, 0); 284562306a36Sopenharmony_ciMODULE_PARM_DESC(irq_coalesce, "use interrupt coalescing (default 1)"); 284662306a36Sopenharmony_cimodule_param(sdh, bool, 0); 284762306a36Sopenharmony_ciMODULE_PARM_DESC(sdh, "use SDH framing (default 0)"); 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_cistatic const struct pci_device_id he_pci_tbl[] = { 285062306a36Sopenharmony_ci { PCI_VDEVICE(FORE, PCI_DEVICE_ID_FORE_HE), 0 }, 285162306a36Sopenharmony_ci { 0, } 285262306a36Sopenharmony_ci}; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, he_pci_tbl); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_cistatic struct pci_driver he_driver = { 285762306a36Sopenharmony_ci .name = "he", 285862306a36Sopenharmony_ci .probe = he_init_one, 285962306a36Sopenharmony_ci .remove = he_remove_one, 286062306a36Sopenharmony_ci .id_table = he_pci_tbl, 286162306a36Sopenharmony_ci}; 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_cimodule_pci_driver(he_driver); 2864