18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * nicstar.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. 88c2ecf20Sopenharmony_ci * It was taken from the frle-0.22 device driver. 98c2ecf20Sopenharmony_ci * As the file doesn't have a copyright notice, in the file 108c2ecf20Sopenharmony_ci * nicstarmac.copyright I put the copyright notice from the 118c2ecf20Sopenharmony_ci * frle-0.22 device driver. 128c2ecf20Sopenharmony_ci * Some code is based on the nicstar driver by M. Welsh. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Author: Rui Prior (rprior@inescn.pt) 158c2ecf20Sopenharmony_ci * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * (C) INESC 1999 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * IMPORTANT INFORMATION 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * There are currently three types of spinlocks: 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * 1 - Per card interrupt spinlock (to protect structures and such) 278c2ecf20Sopenharmony_ci * 2 - Per SCQ scq spinlock 288c2ecf20Sopenharmony_ci * 3 - Per card resource spinlock (to access registers, etc.) 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * These must NEVER be grabbed in reverse order. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Header files */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/module.h> 378c2ecf20Sopenharmony_ci#include <linux/kernel.h> 388c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 398c2ecf20Sopenharmony_ci#include <linux/atmdev.h> 408c2ecf20Sopenharmony_ci#include <linux/atm.h> 418c2ecf20Sopenharmony_ci#include <linux/pci.h> 428c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 438c2ecf20Sopenharmony_ci#include <linux/types.h> 448c2ecf20Sopenharmony_ci#include <linux/string.h> 458c2ecf20Sopenharmony_ci#include <linux/delay.h> 468c2ecf20Sopenharmony_ci#include <linux/init.h> 478c2ecf20Sopenharmony_ci#include <linux/sched.h> 488c2ecf20Sopenharmony_ci#include <linux/timer.h> 498c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 508c2ecf20Sopenharmony_ci#include <linux/bitops.h> 518c2ecf20Sopenharmony_ci#include <linux/slab.h> 528c2ecf20Sopenharmony_ci#include <linux/idr.h> 538c2ecf20Sopenharmony_ci#include <asm/io.h> 548c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 558c2ecf20Sopenharmony_ci#include <linux/atomic.h> 568c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 578c2ecf20Sopenharmony_ci#include "nicstar.h" 588c2ecf20Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_SUNI 598c2ecf20Sopenharmony_ci#include "suni.h" 608c2ecf20Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ 618c2ecf20Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 628c2ecf20Sopenharmony_ci#include "idt77105.h" 638c2ecf20Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Additional code */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#include "nicstarmac.c" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Configurable parameters */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#undef PHY_LOOPBACK 728c2ecf20Sopenharmony_ci#undef TX_DEBUG 738c2ecf20Sopenharmony_ci#undef RX_DEBUG 748c2ecf20Sopenharmony_ci#undef GENERAL_DEBUG 758c2ecf20Sopenharmony_ci#undef EXTRA_DEBUG 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Do not touch these */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#ifdef TX_DEBUG 808c2ecf20Sopenharmony_ci#define TXPRINTK(args...) printk(args) 818c2ecf20Sopenharmony_ci#else 828c2ecf20Sopenharmony_ci#define TXPRINTK(args...) 838c2ecf20Sopenharmony_ci#endif /* TX_DEBUG */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#ifdef RX_DEBUG 868c2ecf20Sopenharmony_ci#define RXPRINTK(args...) printk(args) 878c2ecf20Sopenharmony_ci#else 888c2ecf20Sopenharmony_ci#define RXPRINTK(args...) 898c2ecf20Sopenharmony_ci#endif /* RX_DEBUG */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#ifdef GENERAL_DEBUG 928c2ecf20Sopenharmony_ci#define PRINTK(args...) printk(args) 938c2ecf20Sopenharmony_ci#else 948c2ecf20Sopenharmony_ci#define PRINTK(args...) do {} while (0) 958c2ecf20Sopenharmony_ci#endif /* GENERAL_DEBUG */ 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#ifdef EXTRA_DEBUG 988c2ecf20Sopenharmony_ci#define XPRINTK(args...) printk(args) 998c2ecf20Sopenharmony_ci#else 1008c2ecf20Sopenharmony_ci#define XPRINTK(args...) 1018c2ecf20Sopenharmony_ci#endif /* EXTRA_DEBUG */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* Macros */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define NS_DELAY mdelay(1) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define PTR_DIFF(a, b) ((u32)((unsigned long)(a) - (unsigned long)(b))) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#ifndef ATM_SKB 1128c2ecf20Sopenharmony_ci#define ATM_SKB(s) (&(s)->atm) 1138c2ecf20Sopenharmony_ci#endif 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define scq_virt_to_bus(scq, p) \ 1168c2ecf20Sopenharmony_ci (scq->dma + ((unsigned long)(p) - (unsigned long)(scq)->org)) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Function declarations */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic u32 ns_read_sram(ns_dev * card, u32 sram_address); 1218c2ecf20Sopenharmony_cistatic void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value, 1228c2ecf20Sopenharmony_ci int count); 1238c2ecf20Sopenharmony_cistatic int ns_init_card(int i, struct pci_dev *pcidev); 1248c2ecf20Sopenharmony_cistatic void ns_init_card_error(ns_dev * card, int error); 1258c2ecf20Sopenharmony_cistatic scq_info *get_scq(ns_dev *card, int size, u32 scd); 1268c2ecf20Sopenharmony_cistatic void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc); 1278c2ecf20Sopenharmony_cistatic void push_rxbufs(ns_dev *, struct sk_buff *); 1288c2ecf20Sopenharmony_cistatic irqreturn_t ns_irq_handler(int irq, void *dev_id); 1298c2ecf20Sopenharmony_cistatic int ns_open(struct atm_vcc *vcc); 1308c2ecf20Sopenharmony_cistatic void ns_close(struct atm_vcc *vcc); 1318c2ecf20Sopenharmony_cistatic void fill_tst(ns_dev * card, int n, vc_map * vc); 1328c2ecf20Sopenharmony_cistatic int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); 1338c2ecf20Sopenharmony_cistatic int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, 1348c2ecf20Sopenharmony_ci struct sk_buff *skb); 1358c2ecf20Sopenharmony_cistatic void process_tsq(ns_dev * card); 1368c2ecf20Sopenharmony_cistatic void drain_scq(ns_dev * card, scq_info * scq, int pos); 1378c2ecf20Sopenharmony_cistatic void process_rsq(ns_dev * card); 1388c2ecf20Sopenharmony_cistatic void dequeue_rx(ns_dev * card, ns_rsqe * rsqe); 1398c2ecf20Sopenharmony_cistatic void recycle_rx_buf(ns_dev * card, struct sk_buff *skb); 1408c2ecf20Sopenharmony_cistatic void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count); 1418c2ecf20Sopenharmony_cistatic void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb); 1428c2ecf20Sopenharmony_cistatic void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb); 1438c2ecf20Sopenharmony_cistatic void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb); 1448c2ecf20Sopenharmony_cistatic int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page); 1458c2ecf20Sopenharmony_cistatic int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg); 1468c2ecf20Sopenharmony_ci#ifdef EXTRA_DEBUG 1478c2ecf20Sopenharmony_cistatic void which_list(ns_dev * card, struct sk_buff *skb); 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_cistatic void ns_poll(struct timer_list *unused); 1508c2ecf20Sopenharmony_cistatic void ns_phy_put(struct atm_dev *dev, unsigned char value, 1518c2ecf20Sopenharmony_ci unsigned long addr); 1528c2ecf20Sopenharmony_cistatic unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* Global variables */ 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct ns_dev *cards[NS_MAX_CARDS]; 1578c2ecf20Sopenharmony_cistatic unsigned num_cards; 1588c2ecf20Sopenharmony_cistatic const struct atmdev_ops atm_ops = { 1598c2ecf20Sopenharmony_ci .open = ns_open, 1608c2ecf20Sopenharmony_ci .close = ns_close, 1618c2ecf20Sopenharmony_ci .ioctl = ns_ioctl, 1628c2ecf20Sopenharmony_ci .send = ns_send, 1638c2ecf20Sopenharmony_ci .phy_put = ns_phy_put, 1648c2ecf20Sopenharmony_ci .phy_get = ns_phy_get, 1658c2ecf20Sopenharmony_ci .proc_read = ns_proc_read, 1668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct timer_list ns_timer; 1708c2ecf20Sopenharmony_cistatic char *mac[NS_MAX_CARDS]; 1718c2ecf20Sopenharmony_cimodule_param_array(mac, charp, NULL, 0); 1728c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* Functions */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int nicstar_init_one(struct pci_dev *pcidev, 1778c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci static int index = -1; 1808c2ecf20Sopenharmony_ci unsigned int error; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci index++; 1838c2ecf20Sopenharmony_ci cards[index] = NULL; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci error = ns_init_card(index, pcidev); 1868c2ecf20Sopenharmony_ci if (error) { 1878c2ecf20Sopenharmony_ci cards[index--] = NULL; /* don't increment index */ 1888c2ecf20Sopenharmony_ci goto err_out; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_cierr_out: 1938c2ecf20Sopenharmony_ci return -ENODEV; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void nicstar_remove_one(struct pci_dev *pcidev) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int i, j; 1998c2ecf20Sopenharmony_ci ns_dev *card = pci_get_drvdata(pcidev); 2008c2ecf20Sopenharmony_ci struct sk_buff *hb; 2018c2ecf20Sopenharmony_ci struct sk_buff *iovb; 2028c2ecf20Sopenharmony_ci struct sk_buff *lb; 2038c2ecf20Sopenharmony_ci struct sk_buff *sb; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci i = card->index; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (cards[i] == NULL) 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (card->atmdev->phy && card->atmdev->phy->stop) 2118c2ecf20Sopenharmony_ci card->atmdev->phy->stop(card->atmdev); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Stop everything */ 2148c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + CFG); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* De-register device */ 2178c2ecf20Sopenharmony_ci atm_dev_deregister(card->atmdev); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Disable PCI device */ 2208c2ecf20Sopenharmony_ci pci_disable_device(pcidev); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Free up resources */ 2238c2ecf20Sopenharmony_ci j = 0; 2248c2ecf20Sopenharmony_ci PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); 2258c2ecf20Sopenharmony_ci while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) { 2268c2ecf20Sopenharmony_ci dev_kfree_skb_any(hb); 2278c2ecf20Sopenharmony_ci j++; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); 2308c2ecf20Sopenharmony_ci j = 0; 2318c2ecf20Sopenharmony_ci PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, 2328c2ecf20Sopenharmony_ci card->iovpool.count); 2338c2ecf20Sopenharmony_ci while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) { 2348c2ecf20Sopenharmony_ci dev_kfree_skb_any(iovb); 2358c2ecf20Sopenharmony_ci j++; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); 2388c2ecf20Sopenharmony_ci while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) 2398c2ecf20Sopenharmony_ci dev_kfree_skb_any(lb); 2408c2ecf20Sopenharmony_ci while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) 2418c2ecf20Sopenharmony_ci dev_kfree_skb_any(sb); 2428c2ecf20Sopenharmony_ci free_scq(card, card->scq0, NULL); 2438c2ecf20Sopenharmony_ci for (j = 0; j < NS_FRSCD_NUM; j++) { 2448c2ecf20Sopenharmony_ci if (card->scd2vc[j] != NULL) 2458c2ecf20Sopenharmony_ci free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci idr_destroy(&card->idr); 2488c2ecf20Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, 2498c2ecf20Sopenharmony_ci card->rsq.org, card->rsq.dma); 2508c2ecf20Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, 2518c2ecf20Sopenharmony_ci card->tsq.org, card->tsq.dma); 2528c2ecf20Sopenharmony_ci free_irq(card->pcidev->irq, card); 2538c2ecf20Sopenharmony_ci iounmap(card->membase); 2548c2ecf20Sopenharmony_ci kfree(card); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic const struct pci_device_id nicstar_pci_tbl[] = { 2588c2ecf20Sopenharmony_ci { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77201), 0 }, 2598c2ecf20Sopenharmony_ci {0,} /* terminate list */ 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nicstar_pci_tbl); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic struct pci_driver nicstar_driver = { 2658c2ecf20Sopenharmony_ci .name = "nicstar", 2668c2ecf20Sopenharmony_ci .id_table = nicstar_pci_tbl, 2678c2ecf20Sopenharmony_ci .probe = nicstar_init_one, 2688c2ecf20Sopenharmony_ci .remove = nicstar_remove_one, 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int __init nicstar_init(void) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci unsigned error = 0; /* Initialized to remove compile warning */ 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci XPRINTK("nicstar: nicstar_init() called.\n"); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci error = pci_register_driver(&nicstar_driver); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci TXPRINTK("nicstar: TX debug enabled.\n"); 2808c2ecf20Sopenharmony_ci RXPRINTK("nicstar: RX debug enabled.\n"); 2818c2ecf20Sopenharmony_ci PRINTK("nicstar: General debug enabled.\n"); 2828c2ecf20Sopenharmony_ci#ifdef PHY_LOOPBACK 2838c2ecf20Sopenharmony_ci printk("nicstar: using PHY loopback.\n"); 2848c2ecf20Sopenharmony_ci#endif /* PHY_LOOPBACK */ 2858c2ecf20Sopenharmony_ci XPRINTK("nicstar: nicstar_init() returned.\n"); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!error) { 2888c2ecf20Sopenharmony_ci timer_setup(&ns_timer, ns_poll, 0); 2898c2ecf20Sopenharmony_ci ns_timer.expires = jiffies + NS_POLL_PERIOD; 2908c2ecf20Sopenharmony_ci add_timer(&ns_timer); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return error; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void __exit nicstar_cleanup(void) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci XPRINTK("nicstar: nicstar_cleanup() called.\n"); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci del_timer_sync(&ns_timer); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci pci_unregister_driver(&nicstar_driver); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci XPRINTK("nicstar: nicstar_cleanup() returned.\n"); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic u32 ns_read_sram(ns_dev * card, u32 sram_address) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci unsigned long flags; 3108c2ecf20Sopenharmony_ci u32 data; 3118c2ecf20Sopenharmony_ci sram_address <<= 2; 3128c2ecf20Sopenharmony_ci sram_address &= 0x0007FFFC; /* address must be dword aligned */ 3138c2ecf20Sopenharmony_ci sram_address |= 0x50000000; /* SRAM read command */ 3148c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 3158c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 3168c2ecf20Sopenharmony_ci writel(sram_address, card->membase + CMD); 3178c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 3188c2ecf20Sopenharmony_ci data = readl(card->membase + DR0); 3198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 3208c2ecf20Sopenharmony_ci return data; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value, 3248c2ecf20Sopenharmony_ci int count) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci unsigned long flags; 3278c2ecf20Sopenharmony_ci int i, c; 3288c2ecf20Sopenharmony_ci count--; /* count range now is 0..3 instead of 1..4 */ 3298c2ecf20Sopenharmony_ci c = count; 3308c2ecf20Sopenharmony_ci c <<= 2; /* to use increments of 4 */ 3318c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 3328c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 3338c2ecf20Sopenharmony_ci for (i = 0; i <= c; i += 4) 3348c2ecf20Sopenharmony_ci writel(*(value++), card->membase + i); 3358c2ecf20Sopenharmony_ci /* Note: DR# registers are the first 4 dwords in nicstar's memspace, 3368c2ecf20Sopenharmony_ci so card->membase + DR0 == card->membase */ 3378c2ecf20Sopenharmony_ci sram_address <<= 2; 3388c2ecf20Sopenharmony_ci sram_address &= 0x0007FFFC; 3398c2ecf20Sopenharmony_ci sram_address |= (0x40000000 | count); 3408c2ecf20Sopenharmony_ci writel(sram_address, card->membase + CMD); 3418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int ns_init_card(int i, struct pci_dev *pcidev) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci int j; 3478c2ecf20Sopenharmony_ci struct ns_dev *card = NULL; 3488c2ecf20Sopenharmony_ci unsigned char pci_latency; 3498c2ecf20Sopenharmony_ci unsigned error; 3508c2ecf20Sopenharmony_ci u32 data; 3518c2ecf20Sopenharmony_ci u32 u32d[4]; 3528c2ecf20Sopenharmony_ci u32 ns_cfg_rctsize; 3538c2ecf20Sopenharmony_ci int bcount; 3548c2ecf20Sopenharmony_ci unsigned long membase; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci error = 0; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (pci_enable_device(pcidev)) { 3598c2ecf20Sopenharmony_ci printk("nicstar%d: can't enable PCI device\n", i); 3608c2ecf20Sopenharmony_ci error = 2; 3618c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 3628c2ecf20Sopenharmony_ci return error; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)) != 0) { 3658c2ecf20Sopenharmony_ci printk(KERN_WARNING 3668c2ecf20Sopenharmony_ci "nicstar%d: No suitable DMA available.\n", i); 3678c2ecf20Sopenharmony_ci error = 2; 3688c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 3698c2ecf20Sopenharmony_ci return error; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci card = kmalloc(sizeof(*card), GFP_KERNEL); 3738c2ecf20Sopenharmony_ci if (!card) { 3748c2ecf20Sopenharmony_ci printk 3758c2ecf20Sopenharmony_ci ("nicstar%d: can't allocate memory for device structure.\n", 3768c2ecf20Sopenharmony_ci i); 3778c2ecf20Sopenharmony_ci error = 2; 3788c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 3798c2ecf20Sopenharmony_ci return error; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci cards[i] = card; 3828c2ecf20Sopenharmony_ci spin_lock_init(&card->int_lock); 3838c2ecf20Sopenharmony_ci spin_lock_init(&card->res_lock); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci pci_set_drvdata(pcidev, card); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci card->index = i; 3888c2ecf20Sopenharmony_ci card->atmdev = NULL; 3898c2ecf20Sopenharmony_ci card->pcidev = pcidev; 3908c2ecf20Sopenharmony_ci membase = pci_resource_start(pcidev, 1); 3918c2ecf20Sopenharmony_ci card->membase = ioremap(membase, NS_IOREMAP_SIZE); 3928c2ecf20Sopenharmony_ci if (!card->membase) { 3938c2ecf20Sopenharmony_ci printk("nicstar%d: can't ioremap() membase.\n", i); 3948c2ecf20Sopenharmony_ci error = 3; 3958c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 3968c2ecf20Sopenharmony_ci return error; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci PRINTK("nicstar%d: membase at 0x%p.\n", i, card->membase); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci pci_set_master(pcidev); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) { 4038c2ecf20Sopenharmony_ci printk("nicstar%d: can't read PCI latency timer.\n", i); 4048c2ecf20Sopenharmony_ci error = 6; 4058c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 4068c2ecf20Sopenharmony_ci return error; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci#ifdef NS_PCI_LATENCY 4098c2ecf20Sopenharmony_ci if (pci_latency < NS_PCI_LATENCY) { 4108c2ecf20Sopenharmony_ci PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, 4118c2ecf20Sopenharmony_ci NS_PCI_LATENCY); 4128c2ecf20Sopenharmony_ci for (j = 1; j < 4; j++) { 4138c2ecf20Sopenharmony_ci if (pci_write_config_byte 4148c2ecf20Sopenharmony_ci (pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0) 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci if (j == 4) { 4188c2ecf20Sopenharmony_ci printk 4198c2ecf20Sopenharmony_ci ("nicstar%d: can't set PCI latency timer to %d.\n", 4208c2ecf20Sopenharmony_ci i, NS_PCI_LATENCY); 4218c2ecf20Sopenharmony_ci error = 7; 4228c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 4238c2ecf20Sopenharmony_ci return error; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci#endif /* NS_PCI_LATENCY */ 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Clear timer overflow */ 4298c2ecf20Sopenharmony_ci data = readl(card->membase + STAT); 4308c2ecf20Sopenharmony_ci if (data & NS_STAT_TMROF) 4318c2ecf20Sopenharmony_ci writel(NS_STAT_TMROF, card->membase + STAT); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Software reset */ 4348c2ecf20Sopenharmony_ci writel(NS_CFG_SWRST, card->membase + CFG); 4358c2ecf20Sopenharmony_ci NS_DELAY; 4368c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + CFG); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* PHY reset */ 4398c2ecf20Sopenharmony_ci writel(0x00000008, card->membase + GP); 4408c2ecf20Sopenharmony_ci NS_DELAY; 4418c2ecf20Sopenharmony_ci writel(0x00000001, card->membase + GP); 4428c2ecf20Sopenharmony_ci NS_DELAY; 4438c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 4448c2ecf20Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ 4458c2ecf20Sopenharmony_ci NS_DELAY; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Detect PHY type */ 4488c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 4498c2ecf20Sopenharmony_ci writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); 4508c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 4518c2ecf20Sopenharmony_ci data = readl(card->membase + DR0); 4528c2ecf20Sopenharmony_ci switch (data) { 4538c2ecf20Sopenharmony_ci case 0x00000009: 4548c2ecf20Sopenharmony_ci printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); 4558c2ecf20Sopenharmony_ci card->max_pcr = ATM_25_PCR; 4568c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 4578c2ecf20Sopenharmony_ci writel(0x00000008, card->membase + DR0); 4588c2ecf20Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); 4598c2ecf20Sopenharmony_ci /* Clear an eventual pending interrupt */ 4608c2ecf20Sopenharmony_ci writel(NS_STAT_SFBQF, card->membase + STAT); 4618c2ecf20Sopenharmony_ci#ifdef PHY_LOOPBACK 4628c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 4638c2ecf20Sopenharmony_ci writel(0x00000022, card->membase + DR0); 4648c2ecf20Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); 4658c2ecf20Sopenharmony_ci#endif /* PHY_LOOPBACK */ 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case 0x00000030: 4688c2ecf20Sopenharmony_ci case 0x00000031: 4698c2ecf20Sopenharmony_ci printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); 4708c2ecf20Sopenharmony_ci card->max_pcr = ATM_OC3_PCR; 4718c2ecf20Sopenharmony_ci#ifdef PHY_LOOPBACK 4728c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 4738c2ecf20Sopenharmony_ci writel(0x00000002, card->membase + DR0); 4748c2ecf20Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); 4758c2ecf20Sopenharmony_ci#endif /* PHY_LOOPBACK */ 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci default: 4788c2ecf20Sopenharmony_ci printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data); 4798c2ecf20Sopenharmony_ci error = 8; 4808c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 4818c2ecf20Sopenharmony_ci return error; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + GP); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Determine SRAM size */ 4868c2ecf20Sopenharmony_ci data = 0x76543210; 4878c2ecf20Sopenharmony_ci ns_write_sram(card, 0x1C003, &data, 1); 4888c2ecf20Sopenharmony_ci data = 0x89ABCDEF; 4898c2ecf20Sopenharmony_ci ns_write_sram(card, 0x14003, &data, 1); 4908c2ecf20Sopenharmony_ci if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && 4918c2ecf20Sopenharmony_ci ns_read_sram(card, 0x1C003) == 0x76543210) 4928c2ecf20Sopenharmony_ci card->sram_size = 128; 4938c2ecf20Sopenharmony_ci else 4948c2ecf20Sopenharmony_ci card->sram_size = 32; 4958c2ecf20Sopenharmony_ci PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci card->rct_size = NS_MAX_RCTSIZE; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci#if (NS_MAX_RCTSIZE == 4096) 5008c2ecf20Sopenharmony_ci if (card->sram_size == 128) 5018c2ecf20Sopenharmony_ci printk 5028c2ecf20Sopenharmony_ci ("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", 5038c2ecf20Sopenharmony_ci i); 5048c2ecf20Sopenharmony_ci#elif (NS_MAX_RCTSIZE == 16384) 5058c2ecf20Sopenharmony_ci if (card->sram_size == 32) { 5068c2ecf20Sopenharmony_ci printk 5078c2ecf20Sopenharmony_ci ("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", 5088c2ecf20Sopenharmony_ci i); 5098c2ecf20Sopenharmony_ci card->rct_size = 4096; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci#else 5128c2ecf20Sopenharmony_ci#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c 5138c2ecf20Sopenharmony_ci#endif 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci card->vpibits = NS_VPIBITS; 5168c2ecf20Sopenharmony_ci if (card->rct_size == 4096) 5178c2ecf20Sopenharmony_ci card->vcibits = 12 - NS_VPIBITS; 5188c2ecf20Sopenharmony_ci else /* card->rct_size == 16384 */ 5198c2ecf20Sopenharmony_ci card->vcibits = 14 - NS_VPIBITS; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ 5228c2ecf20Sopenharmony_ci if (mac[i] == NULL) 5238c2ecf20Sopenharmony_ci nicstar_init_eprom(card->membase); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ 5268c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + VPM); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci card->intcnt = 0; 5298c2ecf20Sopenharmony_ci if (request_irq 5308c2ecf20Sopenharmony_ci (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) { 5318c2ecf20Sopenharmony_ci pr_err("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq); 5328c2ecf20Sopenharmony_ci error = 9; 5338c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 5348c2ecf20Sopenharmony_ci return error; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* Initialize TSQ */ 5388c2ecf20Sopenharmony_ci card->tsq.org = dma_alloc_coherent(&card->pcidev->dev, 5398c2ecf20Sopenharmony_ci NS_TSQSIZE + NS_TSQ_ALIGNMENT, 5408c2ecf20Sopenharmony_ci &card->tsq.dma, GFP_KERNEL); 5418c2ecf20Sopenharmony_ci if (card->tsq.org == NULL) { 5428c2ecf20Sopenharmony_ci printk("nicstar%d: can't allocate TSQ.\n", i); 5438c2ecf20Sopenharmony_ci error = 10; 5448c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 5458c2ecf20Sopenharmony_ci return error; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci card->tsq.base = PTR_ALIGN(card->tsq.org, NS_TSQ_ALIGNMENT); 5488c2ecf20Sopenharmony_ci card->tsq.next = card->tsq.base; 5498c2ecf20Sopenharmony_ci card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); 5508c2ecf20Sopenharmony_ci for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) 5518c2ecf20Sopenharmony_ci ns_tsi_init(card->tsq.base + j); 5528c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + TSQH); 5538c2ecf20Sopenharmony_ci writel(ALIGN(card->tsq.dma, NS_TSQ_ALIGNMENT), card->membase + TSQB); 5548c2ecf20Sopenharmony_ci PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Initialize RSQ */ 5578c2ecf20Sopenharmony_ci card->rsq.org = dma_alloc_coherent(&card->pcidev->dev, 5588c2ecf20Sopenharmony_ci NS_RSQSIZE + NS_RSQ_ALIGNMENT, 5598c2ecf20Sopenharmony_ci &card->rsq.dma, GFP_KERNEL); 5608c2ecf20Sopenharmony_ci if (card->rsq.org == NULL) { 5618c2ecf20Sopenharmony_ci printk("nicstar%d: can't allocate RSQ.\n", i); 5628c2ecf20Sopenharmony_ci error = 11; 5638c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 5648c2ecf20Sopenharmony_ci return error; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci card->rsq.base = PTR_ALIGN(card->rsq.org, NS_RSQ_ALIGNMENT); 5678c2ecf20Sopenharmony_ci card->rsq.next = card->rsq.base; 5688c2ecf20Sopenharmony_ci card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); 5698c2ecf20Sopenharmony_ci for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) 5708c2ecf20Sopenharmony_ci ns_rsqe_init(card->rsq.base + j); 5718c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + RSQH); 5728c2ecf20Sopenharmony_ci writel(ALIGN(card->rsq.dma, NS_RSQ_ALIGNMENT), card->membase + RSQB); 5738c2ecf20Sopenharmony_ci PRINTK("nicstar%d: RSQ base at 0x%p.\n", i, card->rsq.base); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* Initialize SCQ0, the only VBR SCQ used */ 5768c2ecf20Sopenharmony_ci card->scq1 = NULL; 5778c2ecf20Sopenharmony_ci card->scq2 = NULL; 5788c2ecf20Sopenharmony_ci card->scq0 = get_scq(card, VBR_SCQSIZE, NS_VRSCD0); 5798c2ecf20Sopenharmony_ci if (card->scq0 == NULL) { 5808c2ecf20Sopenharmony_ci printk("nicstar%d: can't get SCQ0.\n", i); 5818c2ecf20Sopenharmony_ci error = 12; 5828c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 5838c2ecf20Sopenharmony_ci return error; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci u32d[0] = scq_virt_to_bus(card->scq0, card->scq0->base); 5868c2ecf20Sopenharmony_ci u32d[1] = (u32) 0x00000000; 5878c2ecf20Sopenharmony_ci u32d[2] = (u32) 0xffffffff; 5888c2ecf20Sopenharmony_ci u32d[3] = (u32) 0x00000000; 5898c2ecf20Sopenharmony_ci ns_write_sram(card, NS_VRSCD0, u32d, 4); 5908c2ecf20Sopenharmony_ci ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ 5918c2ecf20Sopenharmony_ci ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ 5928c2ecf20Sopenharmony_ci card->scq0->scd = NS_VRSCD0; 5938c2ecf20Sopenharmony_ci PRINTK("nicstar%d: VBR-SCQ0 base at 0x%p.\n", i, card->scq0->base); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Initialize TSTs */ 5968c2ecf20Sopenharmony_ci card->tst_addr = NS_TST0; 5978c2ecf20Sopenharmony_ci card->tst_free_entries = NS_TST_NUM_ENTRIES; 5988c2ecf20Sopenharmony_ci data = NS_TST_OPCODE_VARIABLE; 5998c2ecf20Sopenharmony_ci for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 6008c2ecf20Sopenharmony_ci ns_write_sram(card, NS_TST0 + j, &data, 1); 6018c2ecf20Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); 6028c2ecf20Sopenharmony_ci ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); 6038c2ecf20Sopenharmony_ci for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 6048c2ecf20Sopenharmony_ci ns_write_sram(card, NS_TST1 + j, &data, 1); 6058c2ecf20Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); 6068c2ecf20Sopenharmony_ci ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); 6078c2ecf20Sopenharmony_ci for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 6088c2ecf20Sopenharmony_ci card->tste2vc[j] = NULL; 6098c2ecf20Sopenharmony_ci writel(NS_TST0 << 2, card->membase + TSTB); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Initialize RCT. AAL type is set on opening the VC. */ 6128c2ecf20Sopenharmony_ci#ifdef RCQ_SUPPORT 6138c2ecf20Sopenharmony_ci u32d[0] = NS_RCTE_RAWCELLINTEN; 6148c2ecf20Sopenharmony_ci#else 6158c2ecf20Sopenharmony_ci u32d[0] = 0x00000000; 6168c2ecf20Sopenharmony_ci#endif /* RCQ_SUPPORT */ 6178c2ecf20Sopenharmony_ci u32d[1] = 0x00000000; 6188c2ecf20Sopenharmony_ci u32d[2] = 0x00000000; 6198c2ecf20Sopenharmony_ci u32d[3] = 0xFFFFFFFF; 6208c2ecf20Sopenharmony_ci for (j = 0; j < card->rct_size; j++) 6218c2ecf20Sopenharmony_ci ns_write_sram(card, j * 4, u32d, 4); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci memset(card->vcmap, 0, sizeof(card->vcmap)); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci for (j = 0; j < NS_FRSCD_NUM; j++) 6268c2ecf20Sopenharmony_ci card->scd2vc[j] = NULL; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Initialize buffer levels */ 6298c2ecf20Sopenharmony_ci card->sbnr.min = MIN_SB; 6308c2ecf20Sopenharmony_ci card->sbnr.init = NUM_SB; 6318c2ecf20Sopenharmony_ci card->sbnr.max = MAX_SB; 6328c2ecf20Sopenharmony_ci card->lbnr.min = MIN_LB; 6338c2ecf20Sopenharmony_ci card->lbnr.init = NUM_LB; 6348c2ecf20Sopenharmony_ci card->lbnr.max = MAX_LB; 6358c2ecf20Sopenharmony_ci card->iovnr.min = MIN_IOVB; 6368c2ecf20Sopenharmony_ci card->iovnr.init = NUM_IOVB; 6378c2ecf20Sopenharmony_ci card->iovnr.max = MAX_IOVB; 6388c2ecf20Sopenharmony_ci card->hbnr.min = MIN_HB; 6398c2ecf20Sopenharmony_ci card->hbnr.init = NUM_HB; 6408c2ecf20Sopenharmony_ci card->hbnr.max = MAX_HB; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci card->sm_handle = NULL; 6438c2ecf20Sopenharmony_ci card->sm_addr = 0x00000000; 6448c2ecf20Sopenharmony_ci card->lg_handle = NULL; 6458c2ecf20Sopenharmony_ci card->lg_addr = 0x00000000; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci idr_init(&card->idr); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* Pre-allocate some huge buffers */ 6528c2ecf20Sopenharmony_ci skb_queue_head_init(&card->hbpool.queue); 6538c2ecf20Sopenharmony_ci card->hbpool.count = 0; 6548c2ecf20Sopenharmony_ci for (j = 0; j < NUM_HB; j++) { 6558c2ecf20Sopenharmony_ci struct sk_buff *hb; 6568c2ecf20Sopenharmony_ci hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 6578c2ecf20Sopenharmony_ci if (hb == NULL) { 6588c2ecf20Sopenharmony_ci printk 6598c2ecf20Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d huge buffers.\n", 6608c2ecf20Sopenharmony_ci i, j, NUM_HB); 6618c2ecf20Sopenharmony_ci error = 13; 6628c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 6638c2ecf20Sopenharmony_ci return error; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(hb) = BUF_NONE; 6668c2ecf20Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, hb); 6678c2ecf20Sopenharmony_ci card->hbpool.count++; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* Allocate large buffers */ 6718c2ecf20Sopenharmony_ci skb_queue_head_init(&card->lbpool.queue); 6728c2ecf20Sopenharmony_ci card->lbpool.count = 0; /* Not used */ 6738c2ecf20Sopenharmony_ci for (j = 0; j < NUM_LB; j++) { 6748c2ecf20Sopenharmony_ci struct sk_buff *lb; 6758c2ecf20Sopenharmony_ci lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 6768c2ecf20Sopenharmony_ci if (lb == NULL) { 6778c2ecf20Sopenharmony_ci printk 6788c2ecf20Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d large buffers.\n", 6798c2ecf20Sopenharmony_ci i, j, NUM_LB); 6808c2ecf20Sopenharmony_ci error = 14; 6818c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 6828c2ecf20Sopenharmony_ci return error; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(lb) = BUF_LG; 6858c2ecf20Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, lb); 6868c2ecf20Sopenharmony_ci skb_reserve(lb, NS_SMBUFSIZE); 6878c2ecf20Sopenharmony_ci push_rxbufs(card, lb); 6888c2ecf20Sopenharmony_ci /* Due to the implementation of push_rxbufs() this is 1, not 0 */ 6898c2ecf20Sopenharmony_ci if (j == 1) { 6908c2ecf20Sopenharmony_ci card->rcbuf = lb; 6918c2ecf20Sopenharmony_ci card->rawcell = (struct ns_rcqe *) lb->data; 6928c2ecf20Sopenharmony_ci card->rawch = NS_PRV_DMA(lb); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci /* Test for strange behaviour which leads to crashes */ 6968c2ecf20Sopenharmony_ci if ((bcount = 6978c2ecf20Sopenharmony_ci ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) { 6988c2ecf20Sopenharmony_ci printk 6998c2ecf20Sopenharmony_ci ("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", 7008c2ecf20Sopenharmony_ci i, j, bcount); 7018c2ecf20Sopenharmony_ci error = 14; 7028c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 7038c2ecf20Sopenharmony_ci return error; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Allocate small buffers */ 7078c2ecf20Sopenharmony_ci skb_queue_head_init(&card->sbpool.queue); 7088c2ecf20Sopenharmony_ci card->sbpool.count = 0; /* Not used */ 7098c2ecf20Sopenharmony_ci for (j = 0; j < NUM_SB; j++) { 7108c2ecf20Sopenharmony_ci struct sk_buff *sb; 7118c2ecf20Sopenharmony_ci sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 7128c2ecf20Sopenharmony_ci if (sb == NULL) { 7138c2ecf20Sopenharmony_ci printk 7148c2ecf20Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d small buffers.\n", 7158c2ecf20Sopenharmony_ci i, j, NUM_SB); 7168c2ecf20Sopenharmony_ci error = 15; 7178c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 7188c2ecf20Sopenharmony_ci return error; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(sb) = BUF_SM; 7218c2ecf20Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, sb); 7228c2ecf20Sopenharmony_ci skb_reserve(sb, NS_AAL0_HEADER); 7238c2ecf20Sopenharmony_ci push_rxbufs(card, sb); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci /* Test for strange behaviour which leads to crashes */ 7268c2ecf20Sopenharmony_ci if ((bcount = 7278c2ecf20Sopenharmony_ci ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) { 7288c2ecf20Sopenharmony_ci printk 7298c2ecf20Sopenharmony_ci ("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", 7308c2ecf20Sopenharmony_ci i, j, bcount); 7318c2ecf20Sopenharmony_ci error = 15; 7328c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 7338c2ecf20Sopenharmony_ci return error; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Allocate iovec buffers */ 7378c2ecf20Sopenharmony_ci skb_queue_head_init(&card->iovpool.queue); 7388c2ecf20Sopenharmony_ci card->iovpool.count = 0; 7398c2ecf20Sopenharmony_ci for (j = 0; j < NUM_IOVB; j++) { 7408c2ecf20Sopenharmony_ci struct sk_buff *iovb; 7418c2ecf20Sopenharmony_ci iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); 7428c2ecf20Sopenharmony_ci if (iovb == NULL) { 7438c2ecf20Sopenharmony_ci printk 7448c2ecf20Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d iovec buffers.\n", 7458c2ecf20Sopenharmony_ci i, j, NUM_IOVB); 7468c2ecf20Sopenharmony_ci error = 16; 7478c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 7488c2ecf20Sopenharmony_ci return error; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 7518c2ecf20Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, iovb); 7528c2ecf20Sopenharmony_ci card->iovpool.count++; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Configure NICStAR */ 7568c2ecf20Sopenharmony_ci if (card->rct_size == 4096) 7578c2ecf20Sopenharmony_ci ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; 7588c2ecf20Sopenharmony_ci else /* (card->rct_size == 16384) */ 7598c2ecf20Sopenharmony_ci ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci card->efbie = 1; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* Register device */ 7648c2ecf20Sopenharmony_ci card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops, 7658c2ecf20Sopenharmony_ci -1, NULL); 7668c2ecf20Sopenharmony_ci if (card->atmdev == NULL) { 7678c2ecf20Sopenharmony_ci printk("nicstar%d: can't register device.\n", i); 7688c2ecf20Sopenharmony_ci error = 17; 7698c2ecf20Sopenharmony_ci ns_init_card_error(card, error); 7708c2ecf20Sopenharmony_ci return error; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (mac[i] == NULL || !mac_pton(mac[i], card->atmdev->esi)) { 7748c2ecf20Sopenharmony_ci nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, 7758c2ecf20Sopenharmony_ci card->atmdev->esi, 6); 7768c2ecf20Sopenharmony_ci if (ether_addr_equal(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00")) { 7778c2ecf20Sopenharmony_ci nicstar_read_eprom(card->membase, 7788c2ecf20Sopenharmony_ci NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT, 7798c2ecf20Sopenharmony_ci card->atmdev->esi, 6); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci card->atmdev->dev_data = card; 7868c2ecf20Sopenharmony_ci card->atmdev->ci_range.vpi_bits = card->vpibits; 7878c2ecf20Sopenharmony_ci card->atmdev->ci_range.vci_bits = card->vcibits; 7888c2ecf20Sopenharmony_ci card->atmdev->link_rate = card->max_pcr; 7898c2ecf20Sopenharmony_ci card->atmdev->phy = NULL; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_SUNI 7928c2ecf20Sopenharmony_ci if (card->max_pcr == ATM_OC3_PCR) 7938c2ecf20Sopenharmony_ci suni_init(card->atmdev); 7948c2ecf20Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 7978c2ecf20Sopenharmony_ci if (card->max_pcr == ATM_25_PCR) 7988c2ecf20Sopenharmony_ci idt77105_init(card->atmdev); 7998c2ecf20Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (card->atmdev->phy && card->atmdev->phy->start) 8028c2ecf20Sopenharmony_ci card->atmdev->phy->start(card->atmdev); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci writel(NS_CFG_RXPATH | NS_CFG_SMBUFSIZE | NS_CFG_LGBUFSIZE | NS_CFG_EFBIE | NS_CFG_RSQSIZE | NS_CFG_VPIBITS | ns_cfg_rctsize | NS_CFG_RXINT_NODELAY | NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ 8058c2ecf20Sopenharmony_ci NS_CFG_RSQAFIE | NS_CFG_TXEN | NS_CFG_TXIE | NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ 8068c2ecf20Sopenharmony_ci NS_CFG_PHYIE, card->membase + CFG); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci num_cards++; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return error; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic void ns_init_card_error(ns_dev *card, int error) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci if (error >= 17) { 8168c2ecf20Sopenharmony_ci writel(0x00000000, card->membase + CFG); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci if (error >= 16) { 8198c2ecf20Sopenharmony_ci struct sk_buff *iovb; 8208c2ecf20Sopenharmony_ci while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) 8218c2ecf20Sopenharmony_ci dev_kfree_skb_any(iovb); 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci if (error >= 15) { 8248c2ecf20Sopenharmony_ci struct sk_buff *sb; 8258c2ecf20Sopenharmony_ci while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) 8268c2ecf20Sopenharmony_ci dev_kfree_skb_any(sb); 8278c2ecf20Sopenharmony_ci free_scq(card, card->scq0, NULL); 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci if (error >= 14) { 8308c2ecf20Sopenharmony_ci struct sk_buff *lb; 8318c2ecf20Sopenharmony_ci while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) 8328c2ecf20Sopenharmony_ci dev_kfree_skb_any(lb); 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci if (error >= 13) { 8358c2ecf20Sopenharmony_ci struct sk_buff *hb; 8368c2ecf20Sopenharmony_ci while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) 8378c2ecf20Sopenharmony_ci dev_kfree_skb_any(hb); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci if (error >= 12) { 8408c2ecf20Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, 8418c2ecf20Sopenharmony_ci card->rsq.org, card->rsq.dma); 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci if (error >= 11) { 8448c2ecf20Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, 8458c2ecf20Sopenharmony_ci card->tsq.org, card->tsq.dma); 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci if (error >= 10) { 8488c2ecf20Sopenharmony_ci free_irq(card->pcidev->irq, card); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci if (error >= 4) { 8518c2ecf20Sopenharmony_ci iounmap(card->membase); 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci if (error >= 3) { 8548c2ecf20Sopenharmony_ci pci_disable_device(card->pcidev); 8558c2ecf20Sopenharmony_ci kfree(card); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic scq_info *get_scq(ns_dev *card, int size, u32 scd) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci scq_info *scq; 8628c2ecf20Sopenharmony_ci int i; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) 8658c2ecf20Sopenharmony_ci return NULL; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci scq = kmalloc(sizeof(*scq), GFP_KERNEL); 8688c2ecf20Sopenharmony_ci if (!scq) 8698c2ecf20Sopenharmony_ci return NULL; 8708c2ecf20Sopenharmony_ci scq->org = dma_alloc_coherent(&card->pcidev->dev, 8718c2ecf20Sopenharmony_ci 2 * size, &scq->dma, GFP_KERNEL); 8728c2ecf20Sopenharmony_ci if (!scq->org) { 8738c2ecf20Sopenharmony_ci kfree(scq); 8748c2ecf20Sopenharmony_ci return NULL; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci scq->skb = kmalloc_array(size / NS_SCQE_SIZE, 8778c2ecf20Sopenharmony_ci sizeof(*scq->skb), 8788c2ecf20Sopenharmony_ci GFP_KERNEL); 8798c2ecf20Sopenharmony_ci if (!scq->skb) { 8808c2ecf20Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, 8818c2ecf20Sopenharmony_ci 2 * size, scq->org, scq->dma); 8828c2ecf20Sopenharmony_ci kfree(scq); 8838c2ecf20Sopenharmony_ci return NULL; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci scq->num_entries = size / NS_SCQE_SIZE; 8868c2ecf20Sopenharmony_ci scq->base = PTR_ALIGN(scq->org, size); 8878c2ecf20Sopenharmony_ci scq->next = scq->base; 8888c2ecf20Sopenharmony_ci scq->last = scq->base + (scq->num_entries - 1); 8898c2ecf20Sopenharmony_ci scq->tail = scq->last; 8908c2ecf20Sopenharmony_ci scq->scd = scd; 8918c2ecf20Sopenharmony_ci scq->num_entries = size / NS_SCQE_SIZE; 8928c2ecf20Sopenharmony_ci scq->tbd_count = 0; 8938c2ecf20Sopenharmony_ci init_waitqueue_head(&scq->scqfull_waitq); 8948c2ecf20Sopenharmony_ci scq->full = 0; 8958c2ecf20Sopenharmony_ci spin_lock_init(&scq->lock); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) 8988c2ecf20Sopenharmony_ci scq->skb[i] = NULL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return scq; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci/* For variable rate SCQ vcc must be NULL */ 9048c2ecf20Sopenharmony_cistatic void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci int i; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) 9098c2ecf20Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) { 9108c2ecf20Sopenharmony_ci if (scq->skb[i] != NULL) { 9118c2ecf20Sopenharmony_ci vcc = ATM_SKB(scq->skb[i])->vcc; 9128c2ecf20Sopenharmony_ci if (vcc->pop != NULL) 9138c2ecf20Sopenharmony_ci vcc->pop(vcc, scq->skb[i]); 9148c2ecf20Sopenharmony_ci else 9158c2ecf20Sopenharmony_ci dev_kfree_skb_any(scq->skb[i]); 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } else { /* vcc must be != NULL */ 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (vcc == NULL) { 9208c2ecf20Sopenharmony_ci printk 9218c2ecf20Sopenharmony_ci ("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); 9228c2ecf20Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) 9238c2ecf20Sopenharmony_ci dev_kfree_skb_any(scq->skb[i]); 9248c2ecf20Sopenharmony_ci } else 9258c2ecf20Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) { 9268c2ecf20Sopenharmony_ci if (scq->skb[i] != NULL) { 9278c2ecf20Sopenharmony_ci if (vcc->pop != NULL) 9288c2ecf20Sopenharmony_ci vcc->pop(vcc, scq->skb[i]); 9298c2ecf20Sopenharmony_ci else 9308c2ecf20Sopenharmony_ci dev_kfree_skb_any(scq->skb[i]); 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci kfree(scq->skb); 9358c2ecf20Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, 9368c2ecf20Sopenharmony_ci 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ? 9378c2ecf20Sopenharmony_ci VBR_SCQSIZE : CBR_SCQSIZE), 9388c2ecf20Sopenharmony_ci scq->org, scq->dma); 9398c2ecf20Sopenharmony_ci kfree(scq); 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/* The handles passed must be pointers to the sk_buff containing the small 9438c2ecf20Sopenharmony_ci or large buffer(s) cast to u32. */ 9448c2ecf20Sopenharmony_cistatic void push_rxbufs(ns_dev * card, struct sk_buff *skb) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct sk_buff *handle1, *handle2; 9478c2ecf20Sopenharmony_ci int id1, id2; 9488c2ecf20Sopenharmony_ci u32 addr1, addr2; 9498c2ecf20Sopenharmony_ci u32 stat; 9508c2ecf20Sopenharmony_ci unsigned long flags; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* *BARF* */ 9538c2ecf20Sopenharmony_ci handle2 = NULL; 9548c2ecf20Sopenharmony_ci addr2 = 0; 9558c2ecf20Sopenharmony_ci handle1 = skb; 9568c2ecf20Sopenharmony_ci addr1 = dma_map_single(&card->pcidev->dev, 9578c2ecf20Sopenharmony_ci skb->data, 9588c2ecf20Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM 9598c2ecf20Sopenharmony_ci ? NS_SMSKBSIZE : NS_LGSKBSIZE), 9608c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9618c2ecf20Sopenharmony_ci NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */ 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci#ifdef GENERAL_DEBUG 9648c2ecf20Sopenharmony_ci if (!addr1) 9658c2ecf20Sopenharmony_ci printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", 9668c2ecf20Sopenharmony_ci card->index); 9678c2ecf20Sopenharmony_ci#endif /* GENERAL_DEBUG */ 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci stat = readl(card->membase + STAT); 9708c2ecf20Sopenharmony_ci card->sbfqc = ns_stat_sfbqc_get(stat); 9718c2ecf20Sopenharmony_ci card->lbfqc = ns_stat_lfbqc_get(stat); 9728c2ecf20Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) == BUF_SM) { 9738c2ecf20Sopenharmony_ci if (!addr2) { 9748c2ecf20Sopenharmony_ci if (card->sm_addr) { 9758c2ecf20Sopenharmony_ci addr2 = card->sm_addr; 9768c2ecf20Sopenharmony_ci handle2 = card->sm_handle; 9778c2ecf20Sopenharmony_ci card->sm_addr = 0x00000000; 9788c2ecf20Sopenharmony_ci card->sm_handle = NULL; 9798c2ecf20Sopenharmony_ci } else { /* (!sm_addr) */ 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci card->sm_addr = addr1; 9828c2ecf20Sopenharmony_ci card->sm_handle = handle1; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci } else { /* buf_type == BUF_LG */ 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (!addr2) { 9888c2ecf20Sopenharmony_ci if (card->lg_addr) { 9898c2ecf20Sopenharmony_ci addr2 = card->lg_addr; 9908c2ecf20Sopenharmony_ci handle2 = card->lg_handle; 9918c2ecf20Sopenharmony_ci card->lg_addr = 0x00000000; 9928c2ecf20Sopenharmony_ci card->lg_handle = NULL; 9938c2ecf20Sopenharmony_ci } else { /* (!lg_addr) */ 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci card->lg_addr = addr1; 9968c2ecf20Sopenharmony_ci card->lg_handle = handle1; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (addr2) { 10028c2ecf20Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) == BUF_SM) { 10038c2ecf20Sopenharmony_ci if (card->sbfqc >= card->sbnr.max) { 10048c2ecf20Sopenharmony_ci skb_unlink(handle1, &card->sbpool.queue); 10058c2ecf20Sopenharmony_ci dev_kfree_skb_any(handle1); 10068c2ecf20Sopenharmony_ci skb_unlink(handle2, &card->sbpool.queue); 10078c2ecf20Sopenharmony_ci dev_kfree_skb_any(handle2); 10088c2ecf20Sopenharmony_ci return; 10098c2ecf20Sopenharmony_ci } else 10108c2ecf20Sopenharmony_ci card->sbfqc += 2; 10118c2ecf20Sopenharmony_ci } else { /* (buf_type == BUF_LG) */ 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (card->lbfqc >= card->lbnr.max) { 10148c2ecf20Sopenharmony_ci skb_unlink(handle1, &card->lbpool.queue); 10158c2ecf20Sopenharmony_ci dev_kfree_skb_any(handle1); 10168c2ecf20Sopenharmony_ci skb_unlink(handle2, &card->lbpool.queue); 10178c2ecf20Sopenharmony_ci dev_kfree_skb_any(handle2); 10188c2ecf20Sopenharmony_ci return; 10198c2ecf20Sopenharmony_ci } else 10208c2ecf20Sopenharmony_ci card->lbfqc += 2; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci id1 = idr_alloc(&card->idr, handle1, 0, 0, GFP_ATOMIC); 10248c2ecf20Sopenharmony_ci if (id1 < 0) 10258c2ecf20Sopenharmony_ci goto out; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci id2 = idr_alloc(&card->idr, handle2, 0, 0, GFP_ATOMIC); 10288c2ecf20Sopenharmony_ci if (id2 < 0) 10298c2ecf20Sopenharmony_ci goto out; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 10328c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 10338c2ecf20Sopenharmony_ci writel(addr2, card->membase + DR3); 10348c2ecf20Sopenharmony_ci writel(id2, card->membase + DR2); 10358c2ecf20Sopenharmony_ci writel(addr1, card->membase + DR1); 10368c2ecf20Sopenharmony_ci writel(id1, card->membase + DR0); 10378c2ecf20Sopenharmony_ci writel(NS_CMD_WRITE_FREEBUFQ | NS_PRV_BUFTYPE(skb), 10388c2ecf20Sopenharmony_ci card->membase + CMD); 10398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", 10428c2ecf20Sopenharmony_ci card->index, 10438c2ecf20Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM ? "small" : "large"), 10448c2ecf20Sopenharmony_ci addr1, addr2); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (!card->efbie && card->sbfqc >= card->sbnr.min && 10488c2ecf20Sopenharmony_ci card->lbfqc >= card->lbnr.min) { 10498c2ecf20Sopenharmony_ci card->efbie = 1; 10508c2ecf20Sopenharmony_ci writel((readl(card->membase + CFG) | NS_CFG_EFBIE), 10518c2ecf20Sopenharmony_ci card->membase + CFG); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ciout: 10558c2ecf20Sopenharmony_ci return; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic irqreturn_t ns_irq_handler(int irq, void *dev_id) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci u32 stat_r; 10618c2ecf20Sopenharmony_ci ns_dev *card; 10628c2ecf20Sopenharmony_ci struct atm_dev *dev; 10638c2ecf20Sopenharmony_ci unsigned long flags; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci card = (ns_dev *) dev_id; 10668c2ecf20Sopenharmony_ci dev = card->atmdev; 10678c2ecf20Sopenharmony_ci card->intcnt++; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci stat_r = readl(card->membase + STAT); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* Transmit Status Indicator has been written to T. S. Queue */ 10768c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_TSIF) { 10778c2ecf20Sopenharmony_ci TXPRINTK("nicstar%d: TSI interrupt\n", card->index); 10788c2ecf20Sopenharmony_ci process_tsq(card); 10798c2ecf20Sopenharmony_ci writel(NS_STAT_TSIF, card->membase + STAT); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* Incomplete CS-PDU has been transmitted */ 10838c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_TXICP) { 10848c2ecf20Sopenharmony_ci writel(NS_STAT_TXICP, card->membase + STAT); 10858c2ecf20Sopenharmony_ci TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", 10868c2ecf20Sopenharmony_ci card->index); 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* Transmit Status Queue 7/8 full */ 10908c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_TSQF) { 10918c2ecf20Sopenharmony_ci writel(NS_STAT_TSQF, card->membase + STAT); 10928c2ecf20Sopenharmony_ci PRINTK("nicstar%d: TSQ full.\n", card->index); 10938c2ecf20Sopenharmony_ci process_tsq(card); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Timer overflow */ 10978c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_TMROF) { 10988c2ecf20Sopenharmony_ci writel(NS_STAT_TMROF, card->membase + STAT); 10998c2ecf20Sopenharmony_ci PRINTK("nicstar%d: Timer overflow.\n", card->index); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* PHY device interrupt signal active */ 11038c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_PHYI) { 11048c2ecf20Sopenharmony_ci writel(NS_STAT_PHYI, card->membase + STAT); 11058c2ecf20Sopenharmony_ci PRINTK("nicstar%d: PHY interrupt.\n", card->index); 11068c2ecf20Sopenharmony_ci if (dev->phy && dev->phy->interrupt) { 11078c2ecf20Sopenharmony_ci dev->phy->interrupt(dev); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* Small Buffer Queue is full */ 11128c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_SFBQF) { 11138c2ecf20Sopenharmony_ci writel(NS_STAT_SFBQF, card->membase + STAT); 11148c2ecf20Sopenharmony_ci printk("nicstar%d: Small free buffer queue is full.\n", 11158c2ecf20Sopenharmony_ci card->index); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* Large Buffer Queue is full */ 11198c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_LFBQF) { 11208c2ecf20Sopenharmony_ci writel(NS_STAT_LFBQF, card->membase + STAT); 11218c2ecf20Sopenharmony_ci printk("nicstar%d: Large free buffer queue is full.\n", 11228c2ecf20Sopenharmony_ci card->index); 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* Receive Status Queue is full */ 11268c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_RSQF) { 11278c2ecf20Sopenharmony_ci writel(NS_STAT_RSQF, card->membase + STAT); 11288c2ecf20Sopenharmony_ci printk("nicstar%d: RSQ full.\n", card->index); 11298c2ecf20Sopenharmony_ci process_rsq(card); 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* Complete CS-PDU received */ 11338c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_EOPDU) { 11348c2ecf20Sopenharmony_ci RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); 11358c2ecf20Sopenharmony_ci process_rsq(card); 11368c2ecf20Sopenharmony_ci writel(NS_STAT_EOPDU, card->membase + STAT); 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* Raw cell received */ 11408c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_RAWCF) { 11418c2ecf20Sopenharmony_ci writel(NS_STAT_RAWCF, card->membase + STAT); 11428c2ecf20Sopenharmony_ci#ifndef RCQ_SUPPORT 11438c2ecf20Sopenharmony_ci printk("nicstar%d: Raw cell received and no support yet...\n", 11448c2ecf20Sopenharmony_ci card->index); 11458c2ecf20Sopenharmony_ci#endif /* RCQ_SUPPORT */ 11468c2ecf20Sopenharmony_ci /* NOTE: the following procedure may keep a raw cell pending until the 11478c2ecf20Sopenharmony_ci next interrupt. As this preliminary support is only meant to 11488c2ecf20Sopenharmony_ci avoid buffer leakage, this is not an issue. */ 11498c2ecf20Sopenharmony_ci while (readl(card->membase + RAWCT) != card->rawch) { 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (ns_rcqe_islast(card->rawcell)) { 11528c2ecf20Sopenharmony_ci struct sk_buff *oldbuf; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci oldbuf = card->rcbuf; 11558c2ecf20Sopenharmony_ci card->rcbuf = idr_find(&card->idr, 11568c2ecf20Sopenharmony_ci ns_rcqe_nextbufhandle(card->rawcell)); 11578c2ecf20Sopenharmony_ci card->rawch = NS_PRV_DMA(card->rcbuf); 11588c2ecf20Sopenharmony_ci card->rawcell = (struct ns_rcqe *) 11598c2ecf20Sopenharmony_ci card->rcbuf->data; 11608c2ecf20Sopenharmony_ci recycle_rx_buf(card, oldbuf); 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci card->rawch += NS_RCQE_SIZE; 11638c2ecf20Sopenharmony_ci card->rawcell++; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* Small buffer queue is empty */ 11698c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_SFBQE) { 11708c2ecf20Sopenharmony_ci int i; 11718c2ecf20Sopenharmony_ci struct sk_buff *sb; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci writel(NS_STAT_SFBQE, card->membase + STAT); 11748c2ecf20Sopenharmony_ci printk("nicstar%d: Small free buffer queue empty.\n", 11758c2ecf20Sopenharmony_ci card->index); 11768c2ecf20Sopenharmony_ci for (i = 0; i < card->sbnr.min; i++) { 11778c2ecf20Sopenharmony_ci sb = dev_alloc_skb(NS_SMSKBSIZE); 11788c2ecf20Sopenharmony_ci if (sb == NULL) { 11798c2ecf20Sopenharmony_ci writel(readl(card->membase + CFG) & 11808c2ecf20Sopenharmony_ci ~NS_CFG_EFBIE, card->membase + CFG); 11818c2ecf20Sopenharmony_ci card->efbie = 0; 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(sb) = BUF_SM; 11858c2ecf20Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, sb); 11868c2ecf20Sopenharmony_ci skb_reserve(sb, NS_AAL0_HEADER); 11878c2ecf20Sopenharmony_ci push_rxbufs(card, sb); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci card->sbfqc = i; 11908c2ecf20Sopenharmony_ci process_rsq(card); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* Large buffer queue empty */ 11948c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_LFBQE) { 11958c2ecf20Sopenharmony_ci int i; 11968c2ecf20Sopenharmony_ci struct sk_buff *lb; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci writel(NS_STAT_LFBQE, card->membase + STAT); 11998c2ecf20Sopenharmony_ci printk("nicstar%d: Large free buffer queue empty.\n", 12008c2ecf20Sopenharmony_ci card->index); 12018c2ecf20Sopenharmony_ci for (i = 0; i < card->lbnr.min; i++) { 12028c2ecf20Sopenharmony_ci lb = dev_alloc_skb(NS_LGSKBSIZE); 12038c2ecf20Sopenharmony_ci if (lb == NULL) { 12048c2ecf20Sopenharmony_ci writel(readl(card->membase + CFG) & 12058c2ecf20Sopenharmony_ci ~NS_CFG_EFBIE, card->membase + CFG); 12068c2ecf20Sopenharmony_ci card->efbie = 0; 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(lb) = BUF_LG; 12108c2ecf20Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, lb); 12118c2ecf20Sopenharmony_ci skb_reserve(lb, NS_SMBUFSIZE); 12128c2ecf20Sopenharmony_ci push_rxbufs(card, lb); 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci card->lbfqc = i; 12158c2ecf20Sopenharmony_ci process_rsq(card); 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* Receive Status Queue is 7/8 full */ 12198c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_RSQAF) { 12208c2ecf20Sopenharmony_ci writel(NS_STAT_RSQAF, card->membase + STAT); 12218c2ecf20Sopenharmony_ci RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); 12228c2ecf20Sopenharmony_ci process_rsq(card); 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 12268c2ecf20Sopenharmony_ci PRINTK("nicstar%d: end of interrupt service\n", card->index); 12278c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic int ns_open(struct atm_vcc *vcc) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci ns_dev *card; 12338c2ecf20Sopenharmony_ci vc_map *vc; 12348c2ecf20Sopenharmony_ci unsigned long tmpl, modl; 12358c2ecf20Sopenharmony_ci int tcr, tcra; /* target cell rate, and absolute value */ 12368c2ecf20Sopenharmony_ci int n = 0; /* Number of entries in the TST. Initialized to remove 12378c2ecf20Sopenharmony_ci the compiler warning. */ 12388c2ecf20Sopenharmony_ci u32 u32d[4]; 12398c2ecf20Sopenharmony_ci int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler 12408c2ecf20Sopenharmony_ci warning. How I wish compilers were clever enough to 12418c2ecf20Sopenharmony_ci tell which variables can truly be used 12428c2ecf20Sopenharmony_ci uninitialized... */ 12438c2ecf20Sopenharmony_ci int inuse; /* tx or rx vc already in use by another vcc */ 12448c2ecf20Sopenharmony_ci short vpi = vcc->vpi; 12458c2ecf20Sopenharmony_ci int vci = vcc->vci; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci card = (ns_dev *) vcc->dev->dev_data; 12488c2ecf20Sopenharmony_ci PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi, 12498c2ecf20Sopenharmony_ci vci); 12508c2ecf20Sopenharmony_ci if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { 12518c2ecf20Sopenharmony_ci PRINTK("nicstar%d: unsupported AAL.\n", card->index); 12528c2ecf20Sopenharmony_ci return -EINVAL; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci vc = &(card->vcmap[vpi << card->vcibits | vci]); 12568c2ecf20Sopenharmony_ci vcc->dev_data = vc; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci inuse = 0; 12598c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) 12608c2ecf20Sopenharmony_ci inuse = 1; 12618c2ecf20Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) 12628c2ecf20Sopenharmony_ci inuse += 2; 12638c2ecf20Sopenharmony_ci if (inuse) { 12648c2ecf20Sopenharmony_ci printk("nicstar%d: %s vci already in use.\n", card->index, 12658c2ecf20Sopenharmony_ci inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); 12668c2ecf20Sopenharmony_ci return -EINVAL; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci set_bit(ATM_VF_ADDR, &vcc->flags); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* NOTE: You are not allowed to modify an open connection's QOS. To change 12728c2ecf20Sopenharmony_ci that, remove the ATM_VF_PARTIAL flag checking. There may be other changes 12738c2ecf20Sopenharmony_ci needed to do that. */ 12748c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) { 12758c2ecf20Sopenharmony_ci scq_info *scq; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci set_bit(ATM_VF_PARTIAL, &vcc->flags); 12788c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 12798c2ecf20Sopenharmony_ci /* Check requested cell rate and availability of SCD */ 12808c2ecf20Sopenharmony_ci if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 12818c2ecf20Sopenharmony_ci && vcc->qos.txtp.min_pcr == 0) { 12828c2ecf20Sopenharmony_ci PRINTK 12838c2ecf20Sopenharmony_ci ("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", 12848c2ecf20Sopenharmony_ci card->index); 12858c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 12868c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 12878c2ecf20Sopenharmony_ci return -EINVAL; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci tcr = atm_pcr_goal(&(vcc->qos.txtp)); 12918c2ecf20Sopenharmony_ci tcra = tcr >= 0 ? tcr : -tcr; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci PRINTK("nicstar%d: target cell rate = %d.\n", 12948c2ecf20Sopenharmony_ci card->index, vcc->qos.txtp.max_pcr); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci tmpl = 12978c2ecf20Sopenharmony_ci (unsigned long)tcra *(unsigned long) 12988c2ecf20Sopenharmony_ci NS_TST_NUM_ENTRIES; 12998c2ecf20Sopenharmony_ci modl = tmpl % card->max_pcr; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci n = (int)(tmpl / card->max_pcr); 13028c2ecf20Sopenharmony_ci if (tcr > 0) { 13038c2ecf20Sopenharmony_ci if (modl > 0) 13048c2ecf20Sopenharmony_ci n++; 13058c2ecf20Sopenharmony_ci } else if (tcr == 0) { 13068c2ecf20Sopenharmony_ci if ((n = 13078c2ecf20Sopenharmony_ci (card->tst_free_entries - 13088c2ecf20Sopenharmony_ci NS_TST_RESERVED)) <= 0) { 13098c2ecf20Sopenharmony_ci PRINTK 13108c2ecf20Sopenharmony_ci ("nicstar%d: no CBR bandwidth free.\n", 13118c2ecf20Sopenharmony_ci card->index); 13128c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 13138c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 13148c2ecf20Sopenharmony_ci return -EINVAL; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (n == 0) { 13198c2ecf20Sopenharmony_ci printk 13208c2ecf20Sopenharmony_ci ("nicstar%d: selected bandwidth < granularity.\n", 13218c2ecf20Sopenharmony_ci card->index); 13228c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 13238c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 13248c2ecf20Sopenharmony_ci return -EINVAL; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci if (n > (card->tst_free_entries - NS_TST_RESERVED)) { 13288c2ecf20Sopenharmony_ci PRINTK 13298c2ecf20Sopenharmony_ci ("nicstar%d: not enough free CBR bandwidth.\n", 13308c2ecf20Sopenharmony_ci card->index); 13318c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 13328c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 13338c2ecf20Sopenharmony_ci return -EINVAL; 13348c2ecf20Sopenharmony_ci } else 13358c2ecf20Sopenharmony_ci card->tst_free_entries -= n; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci XPRINTK("nicstar%d: writing %d tst entries.\n", 13388c2ecf20Sopenharmony_ci card->index, n); 13398c2ecf20Sopenharmony_ci for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) { 13408c2ecf20Sopenharmony_ci if (card->scd2vc[frscdi] == NULL) { 13418c2ecf20Sopenharmony_ci card->scd2vc[frscdi] = vc; 13428c2ecf20Sopenharmony_ci break; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci if (frscdi == NS_FRSCD_NUM) { 13468c2ecf20Sopenharmony_ci PRINTK 13478c2ecf20Sopenharmony_ci ("nicstar%d: no SCD available for CBR channel.\n", 13488c2ecf20Sopenharmony_ci card->index); 13498c2ecf20Sopenharmony_ci card->tst_free_entries += n; 13508c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 13518c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 13528c2ecf20Sopenharmony_ci return -EBUSY; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd); 13588c2ecf20Sopenharmony_ci if (scq == NULL) { 13598c2ecf20Sopenharmony_ci PRINTK("nicstar%d: can't get fixed rate SCQ.\n", 13608c2ecf20Sopenharmony_ci card->index); 13618c2ecf20Sopenharmony_ci card->scd2vc[frscdi] = NULL; 13628c2ecf20Sopenharmony_ci card->tst_free_entries += n; 13638c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 13648c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 13658c2ecf20Sopenharmony_ci return -ENOMEM; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci vc->scq = scq; 13688c2ecf20Sopenharmony_ci u32d[0] = scq_virt_to_bus(scq, scq->base); 13698c2ecf20Sopenharmony_ci u32d[1] = (u32) 0x00000000; 13708c2ecf20Sopenharmony_ci u32d[2] = (u32) 0xffffffff; 13718c2ecf20Sopenharmony_ci u32d[3] = (u32) 0x00000000; 13728c2ecf20Sopenharmony_ci ns_write_sram(card, vc->cbr_scd, u32d, 4); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci fill_tst(card, n, vc); 13758c2ecf20Sopenharmony_ci } else if (vcc->qos.txtp.traffic_class == ATM_UBR) { 13768c2ecf20Sopenharmony_ci vc->cbr_scd = 0x00000000; 13778c2ecf20Sopenharmony_ci vc->scq = card->scq0; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 13818c2ecf20Sopenharmony_ci vc->tx = 1; 13828c2ecf20Sopenharmony_ci vc->tx_vcc = vcc; 13838c2ecf20Sopenharmony_ci vc->tbd_count = 0; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE) { 13868c2ecf20Sopenharmony_ci u32 status; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci vc->rx = 1; 13898c2ecf20Sopenharmony_ci vc->rx_vcc = vcc; 13908c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci /* Open the connection in hardware */ 13938c2ecf20Sopenharmony_ci if (vcc->qos.aal == ATM_AAL5) 13948c2ecf20Sopenharmony_ci status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; 13958c2ecf20Sopenharmony_ci else /* vcc->qos.aal == ATM_AAL0 */ 13968c2ecf20Sopenharmony_ci status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; 13978c2ecf20Sopenharmony_ci#ifdef RCQ_SUPPORT 13988c2ecf20Sopenharmony_ci status |= NS_RCTE_RAWCELLINTEN; 13998c2ecf20Sopenharmony_ci#endif /* RCQ_SUPPORT */ 14008c2ecf20Sopenharmony_ci ns_write_sram(card, 14018c2ecf20Sopenharmony_ci NS_RCT + 14028c2ecf20Sopenharmony_ci (vpi << card->vcibits | vci) * 14038c2ecf20Sopenharmony_ci NS_RCT_ENTRY_SIZE, &status, 1); 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci set_bit(ATM_VF_READY, &vcc->flags); 14098c2ecf20Sopenharmony_ci return 0; 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic void ns_close(struct atm_vcc *vcc) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci vc_map *vc; 14158c2ecf20Sopenharmony_ci ns_dev *card; 14168c2ecf20Sopenharmony_ci u32 data; 14178c2ecf20Sopenharmony_ci int i; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci vc = vcc->dev_data; 14208c2ecf20Sopenharmony_ci card = vcc->dev->dev_data; 14218c2ecf20Sopenharmony_ci PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, 14228c2ecf20Sopenharmony_ci (int)vcc->vpi, vcc->vci); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci clear_bit(ATM_VF_READY, &vcc->flags); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE) { 14278c2ecf20Sopenharmony_ci u32 addr; 14288c2ecf20Sopenharmony_ci unsigned long flags; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci addr = 14318c2ecf20Sopenharmony_ci NS_RCT + 14328c2ecf20Sopenharmony_ci (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; 14338c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 14348c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 14358c2ecf20Sopenharmony_ci writel(NS_CMD_CLOSE_CONNECTION | addr << 2, 14368c2ecf20Sopenharmony_ci card->membase + CMD); 14378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci vc->rx = 0; 14408c2ecf20Sopenharmony_ci if (vc->rx_iov != NULL) { 14418c2ecf20Sopenharmony_ci struct sk_buff *iovb; 14428c2ecf20Sopenharmony_ci u32 stat; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci stat = readl(card->membase + STAT); 14458c2ecf20Sopenharmony_ci card->sbfqc = ns_stat_sfbqc_get(stat); 14468c2ecf20Sopenharmony_ci card->lbfqc = ns_stat_lfbqc_get(stat); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci PRINTK 14498c2ecf20Sopenharmony_ci ("nicstar%d: closing a VC with pending rx buffers.\n", 14508c2ecf20Sopenharmony_ci card->index); 14518c2ecf20Sopenharmony_ci iovb = vc->rx_iov; 14528c2ecf20Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 14538c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 14548c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb) = 0; 14558c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 14568c2ecf20Sopenharmony_ci recycle_iov_buf(card, iovb); 14578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 14588c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 14638c2ecf20Sopenharmony_ci vc->tx = 0; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 14678c2ecf20Sopenharmony_ci unsigned long flags; 14688c2ecf20Sopenharmony_ci ns_scqe *scqep; 14698c2ecf20Sopenharmony_ci scq_info *scq; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci scq = vc->scq; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci for (;;) { 14748c2ecf20Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 14758c2ecf20Sopenharmony_ci scqep = scq->next; 14768c2ecf20Sopenharmony_ci if (scqep == scq->base) 14778c2ecf20Sopenharmony_ci scqep = scq->last; 14788c2ecf20Sopenharmony_ci else 14798c2ecf20Sopenharmony_ci scqep--; 14808c2ecf20Sopenharmony_ci if (scqep == scq->tail) { 14818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci /* If the last entry is not a TSR, place one in the SCQ in order to 14858c2ecf20Sopenharmony_ci be able to completely drain it and then close. */ 14868c2ecf20Sopenharmony_ci if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) { 14878c2ecf20Sopenharmony_ci ns_scqe tsr; 14888c2ecf20Sopenharmony_ci u32 scdi, scqi; 14898c2ecf20Sopenharmony_ci u32 data; 14908c2ecf20Sopenharmony_ci int index; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); 14938c2ecf20Sopenharmony_ci scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; 14948c2ecf20Sopenharmony_ci scqi = scq->next - scq->base; 14958c2ecf20Sopenharmony_ci tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); 14968c2ecf20Sopenharmony_ci tsr.word_3 = 0x00000000; 14978c2ecf20Sopenharmony_ci tsr.word_4 = 0x00000000; 14988c2ecf20Sopenharmony_ci *scq->next = tsr; 14998c2ecf20Sopenharmony_ci index = (int)scqi; 15008c2ecf20Sopenharmony_ci scq->skb[index] = NULL; 15018c2ecf20Sopenharmony_ci if (scq->next == scq->last) 15028c2ecf20Sopenharmony_ci scq->next = scq->base; 15038c2ecf20Sopenharmony_ci else 15048c2ecf20Sopenharmony_ci scq->next++; 15058c2ecf20Sopenharmony_ci data = scq_virt_to_bus(scq, scq->next); 15068c2ecf20Sopenharmony_ci ns_write_sram(card, scq->scd, &data, 1); 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 15098c2ecf20Sopenharmony_ci schedule(); 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* Free all TST entries */ 15138c2ecf20Sopenharmony_ci data = NS_TST_OPCODE_VARIABLE; 15148c2ecf20Sopenharmony_ci for (i = 0; i < NS_TST_NUM_ENTRIES; i++) { 15158c2ecf20Sopenharmony_ci if (card->tste2vc[i] == vc) { 15168c2ecf20Sopenharmony_ci ns_write_sram(card, card->tst_addr + i, &data, 15178c2ecf20Sopenharmony_ci 1); 15188c2ecf20Sopenharmony_ci card->tste2vc[i] = NULL; 15198c2ecf20Sopenharmony_ci card->tst_free_entries++; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; 15248c2ecf20Sopenharmony_ci free_scq(card, vc->scq, vcc); 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* remove all references to vcc before deleting it */ 15288c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 15298c2ecf20Sopenharmony_ci unsigned long flags; 15308c2ecf20Sopenharmony_ci scq_info *scq = card->scq0; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) { 15358c2ecf20Sopenharmony_ci if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) { 15368c2ecf20Sopenharmony_ci ATM_SKB(scq->skb[i])->vcc = NULL; 15378c2ecf20Sopenharmony_ci atm_return(vcc, scq->skb[i]->truesize); 15388c2ecf20Sopenharmony_ci PRINTK 15398c2ecf20Sopenharmony_ci ("nicstar: deleted pending vcc mapping\n"); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci vcc->dev_data = NULL; 15478c2ecf20Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 15488c2ecf20Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci#ifdef RX_DEBUG 15518c2ecf20Sopenharmony_ci { 15528c2ecf20Sopenharmony_ci u32 stat, cfg; 15538c2ecf20Sopenharmony_ci stat = readl(card->membase + STAT); 15548c2ecf20Sopenharmony_ci cfg = readl(card->membase + CFG); 15558c2ecf20Sopenharmony_ci printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); 15568c2ecf20Sopenharmony_ci printk 15578c2ecf20Sopenharmony_ci ("TSQ: base = 0x%p next = 0x%p last = 0x%p TSQT = 0x%08X \n", 15588c2ecf20Sopenharmony_ci card->tsq.base, card->tsq.next, 15598c2ecf20Sopenharmony_ci card->tsq.last, readl(card->membase + TSQT)); 15608c2ecf20Sopenharmony_ci printk 15618c2ecf20Sopenharmony_ci ("RSQ: base = 0x%p next = 0x%p last = 0x%p RSQT = 0x%08X \n", 15628c2ecf20Sopenharmony_ci card->rsq.base, card->rsq.next, 15638c2ecf20Sopenharmony_ci card->rsq.last, readl(card->membase + RSQT)); 15648c2ecf20Sopenharmony_ci printk("Empty free buffer queue interrupt %s \n", 15658c2ecf20Sopenharmony_ci card->efbie ? "enabled" : "disabled"); 15668c2ecf20Sopenharmony_ci printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", 15678c2ecf20Sopenharmony_ci ns_stat_sfbqc_get(stat), card->sbpool.count, 15688c2ecf20Sopenharmony_ci ns_stat_lfbqc_get(stat), card->lbpool.count); 15698c2ecf20Sopenharmony_ci printk("hbpool.count = %d iovpool.count = %d \n", 15708c2ecf20Sopenharmony_ci card->hbpool.count, card->iovpool.count); 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci#endif /* RX_DEBUG */ 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_cistatic void fill_tst(ns_dev * card, int n, vc_map * vc) 15768c2ecf20Sopenharmony_ci{ 15778c2ecf20Sopenharmony_ci u32 new_tst; 15788c2ecf20Sopenharmony_ci unsigned long cl; 15798c2ecf20Sopenharmony_ci int e, r; 15808c2ecf20Sopenharmony_ci u32 data; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* It would be very complicated to keep the two TSTs synchronized while 15838c2ecf20Sopenharmony_ci assuring that writes are only made to the inactive TST. So, for now I 15848c2ecf20Sopenharmony_ci will use only one TST. If problems occur, I will change this again */ 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci new_tst = card->tst_addr; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci /* Fill procedure */ 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci for (e = 0; e < NS_TST_NUM_ENTRIES; e++) { 15918c2ecf20Sopenharmony_ci if (card->tste2vc[e] == NULL) 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci if (e == NS_TST_NUM_ENTRIES) { 15958c2ecf20Sopenharmony_ci printk("nicstar%d: No free TST entries found. \n", card->index); 15968c2ecf20Sopenharmony_ci return; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci r = n; 16008c2ecf20Sopenharmony_ci cl = NS_TST_NUM_ENTRIES; 16018c2ecf20Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci while (r > 0) { 16048c2ecf20Sopenharmony_ci if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) { 16058c2ecf20Sopenharmony_ci card->tste2vc[e] = vc; 16068c2ecf20Sopenharmony_ci ns_write_sram(card, new_tst + e, &data, 1); 16078c2ecf20Sopenharmony_ci cl -= NS_TST_NUM_ENTRIES; 16088c2ecf20Sopenharmony_ci r--; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (++e == NS_TST_NUM_ENTRIES) { 16128c2ecf20Sopenharmony_ci e = 0; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci cl += n; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* End of fill procedure */ 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_END, new_tst); 16208c2ecf20Sopenharmony_ci ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); 16218c2ecf20Sopenharmony_ci ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); 16228c2ecf20Sopenharmony_ci card->tst_addr = new_tst; 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_cistatic int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci ns_dev *card; 16288c2ecf20Sopenharmony_ci vc_map *vc; 16298c2ecf20Sopenharmony_ci scq_info *scq; 16308c2ecf20Sopenharmony_ci unsigned long buflen; 16318c2ecf20Sopenharmony_ci ns_scqe scqe; 16328c2ecf20Sopenharmony_ci u32 flags; /* TBD flags, not CPU flags */ 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci card = vcc->dev->dev_data; 16358c2ecf20Sopenharmony_ci TXPRINTK("nicstar%d: ns_send() called.\n", card->index); 16368c2ecf20Sopenharmony_ci if ((vc = (vc_map *) vcc->dev_data) == NULL) { 16378c2ecf20Sopenharmony_ci printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", 16388c2ecf20Sopenharmony_ci card->index); 16398c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 16408c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 16418c2ecf20Sopenharmony_ci return -EINVAL; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (!vc->tx) { 16458c2ecf20Sopenharmony_ci printk("nicstar%d: Trying to transmit on a non-tx VC.\n", 16468c2ecf20Sopenharmony_ci card->index); 16478c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 16488c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 16498c2ecf20Sopenharmony_ci return -EINVAL; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { 16538c2ecf20Sopenharmony_ci printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", 16548c2ecf20Sopenharmony_ci card->index); 16558c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 16568c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 16578c2ecf20Sopenharmony_ci return -EINVAL; 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags != 0) { 16618c2ecf20Sopenharmony_ci printk("nicstar%d: No scatter-gather yet.\n", card->index); 16628c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 16638c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 16648c2ecf20Sopenharmony_ci return -EINVAL; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci NS_PRV_DMA(skb) = dma_map_single(&card->pcidev->dev, skb->data, 16708c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (vcc->qos.aal == ATM_AAL5) { 16738c2ecf20Sopenharmony_ci buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ 16748c2ecf20Sopenharmony_ci flags = NS_TBD_AAL5; 16758c2ecf20Sopenharmony_ci scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb)); 16768c2ecf20Sopenharmony_ci scqe.word_3 = cpu_to_le32(skb->len); 16778c2ecf20Sopenharmony_ci scqe.word_4 = 16788c2ecf20Sopenharmony_ci ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, 16798c2ecf20Sopenharmony_ci ATM_SKB(skb)-> 16808c2ecf20Sopenharmony_ci atm_options & ATM_ATMOPT_CLP ? 1 : 0); 16818c2ecf20Sopenharmony_ci flags |= NS_TBD_EOPDU; 16828c2ecf20Sopenharmony_ci } else { /* (vcc->qos.aal == ATM_AAL0) */ 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ 16858c2ecf20Sopenharmony_ci flags = NS_TBD_AAL0; 16868c2ecf20Sopenharmony_ci scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb) + NS_AAL0_HEADER); 16878c2ecf20Sopenharmony_ci scqe.word_3 = cpu_to_le32(0x00000000); 16888c2ecf20Sopenharmony_ci if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ 16898c2ecf20Sopenharmony_ci flags |= NS_TBD_EOPDU; 16908c2ecf20Sopenharmony_ci scqe.word_4 = 16918c2ecf20Sopenharmony_ci cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK); 16928c2ecf20Sopenharmony_ci /* Force the VPI/VCI to be the same as in VCC struct */ 16938c2ecf20Sopenharmony_ci scqe.word_4 |= 16948c2ecf20Sopenharmony_ci cpu_to_le32((((u32) vcc-> 16958c2ecf20Sopenharmony_ci vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc-> 16968c2ecf20Sopenharmony_ci vci) << 16978c2ecf20Sopenharmony_ci NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK); 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 17018c2ecf20Sopenharmony_ci scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); 17028c2ecf20Sopenharmony_ci scq = ((vc_map *) vcc->dev_data)->scq; 17038c2ecf20Sopenharmony_ci } else { 17048c2ecf20Sopenharmony_ci scqe.word_1 = 17058c2ecf20Sopenharmony_ci ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); 17068c2ecf20Sopenharmony_ci scq = card->scq0; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (push_scqe(card, vc, scq, &scqe, skb) != 0) { 17108c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 17118c2ecf20Sopenharmony_ci dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), skb->len, 17128c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 17138c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 17148c2ecf20Sopenharmony_ci return -EIO; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->tx); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return 0; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_cistatic int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, 17228c2ecf20Sopenharmony_ci struct sk_buff *skb) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci unsigned long flags; 17258c2ecf20Sopenharmony_ci ns_scqe tsr; 17268c2ecf20Sopenharmony_ci u32 scdi, scqi; 17278c2ecf20Sopenharmony_ci int scq_is_vbr; 17288c2ecf20Sopenharmony_ci u32 data; 17298c2ecf20Sopenharmony_ci int index; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 17328c2ecf20Sopenharmony_ci while (scq->tail == scq->next) { 17338c2ecf20Sopenharmony_ci if (in_interrupt()) { 17348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 17358c2ecf20Sopenharmony_ci printk("nicstar%d: Error pushing TBD.\n", card->index); 17368c2ecf20Sopenharmony_ci return 1; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci scq->full = 1; 17408c2ecf20Sopenharmony_ci wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, 17418c2ecf20Sopenharmony_ci scq->tail != scq->next, 17428c2ecf20Sopenharmony_ci scq->lock, 17438c2ecf20Sopenharmony_ci SCQFULL_TIMEOUT); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (scq->full) { 17468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 17478c2ecf20Sopenharmony_ci printk("nicstar%d: Timeout pushing TBD.\n", 17488c2ecf20Sopenharmony_ci card->index); 17498c2ecf20Sopenharmony_ci return 1; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci *scq->next = *tbd; 17538c2ecf20Sopenharmony_ci index = (int)(scq->next - scq->base); 17548c2ecf20Sopenharmony_ci scq->skb[index] = skb; 17558c2ecf20Sopenharmony_ci XPRINTK("nicstar%d: sending skb at 0x%p (pos %d).\n", 17568c2ecf20Sopenharmony_ci card->index, skb, index); 17578c2ecf20Sopenharmony_ci XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n", 17588c2ecf20Sopenharmony_ci card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2), 17598c2ecf20Sopenharmony_ci le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4), 17608c2ecf20Sopenharmony_ci scq->next); 17618c2ecf20Sopenharmony_ci if (scq->next == scq->last) 17628c2ecf20Sopenharmony_ci scq->next = scq->base; 17638c2ecf20Sopenharmony_ci else 17648c2ecf20Sopenharmony_ci scq->next++; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci vc->tbd_count++; 17678c2ecf20Sopenharmony_ci if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) { 17688c2ecf20Sopenharmony_ci scq->tbd_count++; 17698c2ecf20Sopenharmony_ci scq_is_vbr = 1; 17708c2ecf20Sopenharmony_ci } else 17718c2ecf20Sopenharmony_ci scq_is_vbr = 0; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if (vc->tbd_count >= MAX_TBD_PER_VC 17748c2ecf20Sopenharmony_ci || scq->tbd_count >= MAX_TBD_PER_SCQ) { 17758c2ecf20Sopenharmony_ci int has_run = 0; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci while (scq->tail == scq->next) { 17788c2ecf20Sopenharmony_ci if (in_interrupt()) { 17798c2ecf20Sopenharmony_ci data = scq_virt_to_bus(scq, scq->next); 17808c2ecf20Sopenharmony_ci ns_write_sram(card, scq->scd, &data, 1); 17818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 17828c2ecf20Sopenharmony_ci printk("nicstar%d: Error pushing TSR.\n", 17838c2ecf20Sopenharmony_ci card->index); 17848c2ecf20Sopenharmony_ci return 0; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci scq->full = 1; 17888c2ecf20Sopenharmony_ci if (has_run++) 17898c2ecf20Sopenharmony_ci break; 17908c2ecf20Sopenharmony_ci wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, 17918c2ecf20Sopenharmony_ci scq->tail != scq->next, 17928c2ecf20Sopenharmony_ci scq->lock, 17938c2ecf20Sopenharmony_ci SCQFULL_TIMEOUT); 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (!scq->full) { 17978c2ecf20Sopenharmony_ci tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); 17988c2ecf20Sopenharmony_ci if (scq_is_vbr) 17998c2ecf20Sopenharmony_ci scdi = NS_TSR_SCDISVBR; 18008c2ecf20Sopenharmony_ci else 18018c2ecf20Sopenharmony_ci scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; 18028c2ecf20Sopenharmony_ci scqi = scq->next - scq->base; 18038c2ecf20Sopenharmony_ci tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); 18048c2ecf20Sopenharmony_ci tsr.word_3 = 0x00000000; 18058c2ecf20Sopenharmony_ci tsr.word_4 = 0x00000000; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci *scq->next = tsr; 18088c2ecf20Sopenharmony_ci index = (int)scqi; 18098c2ecf20Sopenharmony_ci scq->skb[index] = NULL; 18108c2ecf20Sopenharmony_ci XPRINTK 18118c2ecf20Sopenharmony_ci ("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n", 18128c2ecf20Sopenharmony_ci card->index, le32_to_cpu(tsr.word_1), 18138c2ecf20Sopenharmony_ci le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3), 18148c2ecf20Sopenharmony_ci le32_to_cpu(tsr.word_4), scq->next); 18158c2ecf20Sopenharmony_ci if (scq->next == scq->last) 18168c2ecf20Sopenharmony_ci scq->next = scq->base; 18178c2ecf20Sopenharmony_ci else 18188c2ecf20Sopenharmony_ci scq->next++; 18198c2ecf20Sopenharmony_ci vc->tbd_count = 0; 18208c2ecf20Sopenharmony_ci scq->tbd_count = 0; 18218c2ecf20Sopenharmony_ci } else 18228c2ecf20Sopenharmony_ci PRINTK("nicstar%d: Timeout pushing TSR.\n", 18238c2ecf20Sopenharmony_ci card->index); 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci data = scq_virt_to_bus(scq, scq->next); 18268c2ecf20Sopenharmony_ci ns_write_sram(card, scq->scd, &data, 1); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci return 0; 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic void process_tsq(ns_dev * card) 18348c2ecf20Sopenharmony_ci{ 18358c2ecf20Sopenharmony_ci u32 scdi; 18368c2ecf20Sopenharmony_ci scq_info *scq; 18378c2ecf20Sopenharmony_ci ns_tsi *previous = NULL, *one_ahead, *two_ahead; 18388c2ecf20Sopenharmony_ci int serviced_entries; /* flag indicating at least on entry was serviced */ 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci serviced_entries = 0; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (card->tsq.next == card->tsq.last) 18438c2ecf20Sopenharmony_ci one_ahead = card->tsq.base; 18448c2ecf20Sopenharmony_ci else 18458c2ecf20Sopenharmony_ci one_ahead = card->tsq.next + 1; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci if (one_ahead == card->tsq.last) 18488c2ecf20Sopenharmony_ci two_ahead = card->tsq.base; 18498c2ecf20Sopenharmony_ci else 18508c2ecf20Sopenharmony_ci two_ahead = one_ahead + 1; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) || 18538c2ecf20Sopenharmony_ci !ns_tsi_isempty(two_ahead)) 18548c2ecf20Sopenharmony_ci /* At most two empty, as stated in the 77201 errata */ 18558c2ecf20Sopenharmony_ci { 18568c2ecf20Sopenharmony_ci serviced_entries = 1; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci /* Skip the one or two possible empty entries */ 18598c2ecf20Sopenharmony_ci while (ns_tsi_isempty(card->tsq.next)) { 18608c2ecf20Sopenharmony_ci if (card->tsq.next == card->tsq.last) 18618c2ecf20Sopenharmony_ci card->tsq.next = card->tsq.base; 18628c2ecf20Sopenharmony_ci else 18638c2ecf20Sopenharmony_ci card->tsq.next++; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci if (!ns_tsi_tmrof(card->tsq.next)) { 18678c2ecf20Sopenharmony_ci scdi = ns_tsi_getscdindex(card->tsq.next); 18688c2ecf20Sopenharmony_ci if (scdi == NS_TSI_SCDISVBR) 18698c2ecf20Sopenharmony_ci scq = card->scq0; 18708c2ecf20Sopenharmony_ci else { 18718c2ecf20Sopenharmony_ci if (card->scd2vc[scdi] == NULL) { 18728c2ecf20Sopenharmony_ci printk 18738c2ecf20Sopenharmony_ci ("nicstar%d: could not find VC from SCD index.\n", 18748c2ecf20Sopenharmony_ci card->index); 18758c2ecf20Sopenharmony_ci ns_tsi_init(card->tsq.next); 18768c2ecf20Sopenharmony_ci return; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci scq = card->scd2vc[scdi]->scq; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); 18818c2ecf20Sopenharmony_ci scq->full = 0; 18828c2ecf20Sopenharmony_ci wake_up_interruptible(&(scq->scqfull_waitq)); 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci ns_tsi_init(card->tsq.next); 18868c2ecf20Sopenharmony_ci previous = card->tsq.next; 18878c2ecf20Sopenharmony_ci if (card->tsq.next == card->tsq.last) 18888c2ecf20Sopenharmony_ci card->tsq.next = card->tsq.base; 18898c2ecf20Sopenharmony_ci else 18908c2ecf20Sopenharmony_ci card->tsq.next++; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci if (card->tsq.next == card->tsq.last) 18938c2ecf20Sopenharmony_ci one_ahead = card->tsq.base; 18948c2ecf20Sopenharmony_ci else 18958c2ecf20Sopenharmony_ci one_ahead = card->tsq.next + 1; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci if (one_ahead == card->tsq.last) 18988c2ecf20Sopenharmony_ci two_ahead = card->tsq.base; 18998c2ecf20Sopenharmony_ci else 19008c2ecf20Sopenharmony_ci two_ahead = one_ahead + 1; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci if (serviced_entries) 19048c2ecf20Sopenharmony_ci writel(PTR_DIFF(previous, card->tsq.base), 19058c2ecf20Sopenharmony_ci card->membase + TSQH); 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic void drain_scq(ns_dev * card, scq_info * scq, int pos) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci struct atm_vcc *vcc; 19118c2ecf20Sopenharmony_ci struct sk_buff *skb; 19128c2ecf20Sopenharmony_ci int i; 19138c2ecf20Sopenharmony_ci unsigned long flags; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci XPRINTK("nicstar%d: drain_scq() called, scq at 0x%p, pos %d.\n", 19168c2ecf20Sopenharmony_ci card->index, scq, pos); 19178c2ecf20Sopenharmony_ci if (pos >= scq->num_entries) { 19188c2ecf20Sopenharmony_ci printk("nicstar%d: Bad index on drain_scq().\n", card->index); 19198c2ecf20Sopenharmony_ci return; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 19238c2ecf20Sopenharmony_ci i = (int)(scq->tail - scq->base); 19248c2ecf20Sopenharmony_ci if (++i == scq->num_entries) 19258c2ecf20Sopenharmony_ci i = 0; 19268c2ecf20Sopenharmony_ci while (i != pos) { 19278c2ecf20Sopenharmony_ci skb = scq->skb[i]; 19288c2ecf20Sopenharmony_ci XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n", 19298c2ecf20Sopenharmony_ci card->index, skb, i); 19308c2ecf20Sopenharmony_ci if (skb != NULL) { 19318c2ecf20Sopenharmony_ci dma_unmap_single(&card->pcidev->dev, 19328c2ecf20Sopenharmony_ci NS_PRV_DMA(skb), 19338c2ecf20Sopenharmony_ci skb->len, 19348c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 19358c2ecf20Sopenharmony_ci vcc = ATM_SKB(skb)->vcc; 19368c2ecf20Sopenharmony_ci if (vcc && vcc->pop != NULL) { 19378c2ecf20Sopenharmony_ci vcc->pop(vcc, skb); 19388c2ecf20Sopenharmony_ci } else { 19398c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci scq->skb[i] = NULL; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci if (++i == scq->num_entries) 19448c2ecf20Sopenharmony_ci i = 0; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci scq->tail = scq->base + pos; 19478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 19488c2ecf20Sopenharmony_ci} 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cistatic void process_rsq(ns_dev * card) 19518c2ecf20Sopenharmony_ci{ 19528c2ecf20Sopenharmony_ci ns_rsqe *previous; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (!ns_rsqe_valid(card->rsq.next)) 19558c2ecf20Sopenharmony_ci return; 19568c2ecf20Sopenharmony_ci do { 19578c2ecf20Sopenharmony_ci dequeue_rx(card, card->rsq.next); 19588c2ecf20Sopenharmony_ci ns_rsqe_init(card->rsq.next); 19598c2ecf20Sopenharmony_ci previous = card->rsq.next; 19608c2ecf20Sopenharmony_ci if (card->rsq.next == card->rsq.last) 19618c2ecf20Sopenharmony_ci card->rsq.next = card->rsq.base; 19628c2ecf20Sopenharmony_ci else 19638c2ecf20Sopenharmony_ci card->rsq.next++; 19648c2ecf20Sopenharmony_ci } while (ns_rsqe_valid(card->rsq.next)); 19658c2ecf20Sopenharmony_ci writel(PTR_DIFF(previous, card->rsq.base), card->membase + RSQH); 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci u32 vpi, vci; 19718c2ecf20Sopenharmony_ci vc_map *vc; 19728c2ecf20Sopenharmony_ci struct sk_buff *iovb; 19738c2ecf20Sopenharmony_ci struct iovec *iov; 19748c2ecf20Sopenharmony_ci struct atm_vcc *vcc; 19758c2ecf20Sopenharmony_ci struct sk_buff *skb; 19768c2ecf20Sopenharmony_ci unsigned short aal5_len; 19778c2ecf20Sopenharmony_ci int len; 19788c2ecf20Sopenharmony_ci u32 stat; 19798c2ecf20Sopenharmony_ci u32 id; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci stat = readl(card->membase + STAT); 19828c2ecf20Sopenharmony_ci card->sbfqc = ns_stat_sfbqc_get(stat); 19838c2ecf20Sopenharmony_ci card->lbfqc = ns_stat_lfbqc_get(stat); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci id = le32_to_cpu(rsqe->buffer_handle); 19868c2ecf20Sopenharmony_ci skb = idr_remove(&card->idr, id); 19878c2ecf20Sopenharmony_ci if (!skb) { 19888c2ecf20Sopenharmony_ci RXPRINTK(KERN_ERR 19898c2ecf20Sopenharmony_ci "nicstar%d: skb not found!\n", card->index); 19908c2ecf20Sopenharmony_ci return; 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&card->pcidev->dev, 19938c2ecf20Sopenharmony_ci NS_PRV_DMA(skb), 19948c2ecf20Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM 19958c2ecf20Sopenharmony_ci ? NS_SMSKBSIZE : NS_LGSKBSIZE), 19968c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 19978c2ecf20Sopenharmony_ci dma_unmap_single(&card->pcidev->dev, 19988c2ecf20Sopenharmony_ci NS_PRV_DMA(skb), 19998c2ecf20Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM 20008c2ecf20Sopenharmony_ci ? NS_SMSKBSIZE : NS_LGSKBSIZE), 20018c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 20028c2ecf20Sopenharmony_ci vpi = ns_rsqe_vpi(rsqe); 20038c2ecf20Sopenharmony_ci vci = ns_rsqe_vci(rsqe); 20048c2ecf20Sopenharmony_ci if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) { 20058c2ecf20Sopenharmony_ci printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", 20068c2ecf20Sopenharmony_ci card->index, vpi, vci); 20078c2ecf20Sopenharmony_ci recycle_rx_buf(card, skb); 20088c2ecf20Sopenharmony_ci return; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci vc = &(card->vcmap[vpi << card->vcibits | vci]); 20128c2ecf20Sopenharmony_ci if (!vc->rx) { 20138c2ecf20Sopenharmony_ci RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", 20148c2ecf20Sopenharmony_ci card->index, vpi, vci); 20158c2ecf20Sopenharmony_ci recycle_rx_buf(card, skb); 20168c2ecf20Sopenharmony_ci return; 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci vcc = vc->rx_vcc; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (vcc->qos.aal == ATM_AAL0) { 20228c2ecf20Sopenharmony_ci struct sk_buff *sb; 20238c2ecf20Sopenharmony_ci unsigned char *cell; 20248c2ecf20Sopenharmony_ci int i; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci cell = skb->data; 20278c2ecf20Sopenharmony_ci for (i = ns_rsqe_cellcount(rsqe); i; i--) { 20288c2ecf20Sopenharmony_ci sb = dev_alloc_skb(NS_SMSKBSIZE); 20298c2ecf20Sopenharmony_ci if (!sb) { 20308c2ecf20Sopenharmony_ci printk 20318c2ecf20Sopenharmony_ci ("nicstar%d: Can't allocate buffers for aal0.\n", 20328c2ecf20Sopenharmony_ci card->index); 20338c2ecf20Sopenharmony_ci atomic_add(i, &vcc->stats->rx_drop); 20348c2ecf20Sopenharmony_ci break; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci if (!atm_charge(vcc, sb->truesize)) { 20378c2ecf20Sopenharmony_ci RXPRINTK 20388c2ecf20Sopenharmony_ci ("nicstar%d: atm_charge() dropped aal0 packets.\n", 20398c2ecf20Sopenharmony_ci card->index); 20408c2ecf20Sopenharmony_ci atomic_add(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */ 20418c2ecf20Sopenharmony_ci dev_kfree_skb_any(sb); 20428c2ecf20Sopenharmony_ci break; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci /* Rebuild the header */ 20458c2ecf20Sopenharmony_ci *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 | 20468c2ecf20Sopenharmony_ci (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); 20478c2ecf20Sopenharmony_ci if (i == 1 && ns_rsqe_eopdu(rsqe)) 20488c2ecf20Sopenharmony_ci *((u32 *) sb->data) |= 0x00000002; 20498c2ecf20Sopenharmony_ci skb_put(sb, NS_AAL0_HEADER); 20508c2ecf20Sopenharmony_ci memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD); 20518c2ecf20Sopenharmony_ci skb_put(sb, ATM_CELL_PAYLOAD); 20528c2ecf20Sopenharmony_ci ATM_SKB(sb)->vcc = vcc; 20538c2ecf20Sopenharmony_ci __net_timestamp(sb); 20548c2ecf20Sopenharmony_ci vcc->push(vcc, sb); 20558c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx); 20568c2ecf20Sopenharmony_ci cell += ATM_CELL_PAYLOAD; 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci recycle_rx_buf(card, skb); 20608c2ecf20Sopenharmony_ci return; 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci /* To reach this point, the AAL layer can only be AAL5 */ 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if ((iovb = vc->rx_iov) == NULL) { 20668c2ecf20Sopenharmony_ci iovb = skb_dequeue(&(card->iovpool.queue)); 20678c2ecf20Sopenharmony_ci if (iovb == NULL) { /* No buffers in the queue */ 20688c2ecf20Sopenharmony_ci iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); 20698c2ecf20Sopenharmony_ci if (iovb == NULL) { 20708c2ecf20Sopenharmony_ci printk("nicstar%d: Out of iovec buffers.\n", 20718c2ecf20Sopenharmony_ci card->index); 20728c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 20738c2ecf20Sopenharmony_ci recycle_rx_buf(card, skb); 20748c2ecf20Sopenharmony_ci return; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 20778c2ecf20Sopenharmony_ci } else if (--card->iovpool.count < card->iovnr.min) { 20788c2ecf20Sopenharmony_ci struct sk_buff *new_iovb; 20798c2ecf20Sopenharmony_ci if ((new_iovb = 20808c2ecf20Sopenharmony_ci alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) { 20818c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 20828c2ecf20Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, new_iovb); 20838c2ecf20Sopenharmony_ci card->iovpool.count++; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci vc->rx_iov = iovb; 20878c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb) = 0; 20888c2ecf20Sopenharmony_ci iovb->len = 0; 20898c2ecf20Sopenharmony_ci iovb->data = iovb->head; 20908c2ecf20Sopenharmony_ci skb_reset_tail_pointer(iovb); 20918c2ecf20Sopenharmony_ci /* IMPORTANT: a pointer to the sk_buff containing the small or large 20928c2ecf20Sopenharmony_ci buffer is stored as iovec base, NOT a pointer to the 20938c2ecf20Sopenharmony_ci small or large buffer itself. */ 20948c2ecf20Sopenharmony_ci } else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) { 20958c2ecf20Sopenharmony_ci printk("nicstar%d: received too big AAL5 SDU.\n", card->index); 20968c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 20978c2ecf20Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 20988c2ecf20Sopenharmony_ci NS_MAX_IOVECS); 20998c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb) = 0; 21008c2ecf20Sopenharmony_ci iovb->len = 0; 21018c2ecf20Sopenharmony_ci iovb->data = iovb->head; 21028c2ecf20Sopenharmony_ci skb_reset_tail_pointer(iovb); 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci iov = &((struct iovec *)iovb->data)[NS_PRV_IOVCNT(iovb)++]; 21058c2ecf20Sopenharmony_ci iov->iov_base = (void *)skb; 21068c2ecf20Sopenharmony_ci iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; 21078c2ecf20Sopenharmony_ci iovb->len += iov->iov_len; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci#ifdef EXTRA_DEBUG 21108c2ecf20Sopenharmony_ci if (NS_PRV_IOVCNT(iovb) == 1) { 21118c2ecf20Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) != BUF_SM) { 21128c2ecf20Sopenharmony_ci printk 21138c2ecf20Sopenharmony_ci ("nicstar%d: Expected a small buffer, and this is not one.\n", 21148c2ecf20Sopenharmony_ci card->index); 21158c2ecf20Sopenharmony_ci which_list(card, skb); 21168c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 21178c2ecf20Sopenharmony_ci recycle_rx_buf(card, skb); 21188c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 21198c2ecf20Sopenharmony_ci recycle_iov_buf(card, iovb); 21208c2ecf20Sopenharmony_ci return; 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci } else { /* NS_PRV_IOVCNT(iovb) >= 2 */ 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) != BUF_LG) { 21258c2ecf20Sopenharmony_ci printk 21268c2ecf20Sopenharmony_ci ("nicstar%d: Expected a large buffer, and this is not one.\n", 21278c2ecf20Sopenharmony_ci card->index); 21288c2ecf20Sopenharmony_ci which_list(card, skb); 21298c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 21308c2ecf20Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 21318c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 21328c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 21338c2ecf20Sopenharmony_ci recycle_iov_buf(card, iovb); 21348c2ecf20Sopenharmony_ci return; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci#endif /* EXTRA_DEBUG */ 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci if (ns_rsqe_eopdu(rsqe)) { 21408c2ecf20Sopenharmony_ci /* This works correctly regardless of the endianness of the host */ 21418c2ecf20Sopenharmony_ci unsigned char *L1L2 = (unsigned char *) 21428c2ecf20Sopenharmony_ci (skb->data + iov->iov_len - 6); 21438c2ecf20Sopenharmony_ci aal5_len = L1L2[0] << 8 | L1L2[1]; 21448c2ecf20Sopenharmony_ci len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; 21458c2ecf20Sopenharmony_ci if (ns_rsqe_crcerr(rsqe) || 21468c2ecf20Sopenharmony_ci len + 8 > iovb->len || len + (47 + 8) < iovb->len) { 21478c2ecf20Sopenharmony_ci printk("nicstar%d: AAL5 CRC error", card->index); 21488c2ecf20Sopenharmony_ci if (len + 8 > iovb->len || len + (47 + 8) < iovb->len) 21498c2ecf20Sopenharmony_ci printk(" - PDU size mismatch.\n"); 21508c2ecf20Sopenharmony_ci else 21518c2ecf20Sopenharmony_ci printk(".\n"); 21528c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 21538c2ecf20Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 21548c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 21558c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 21568c2ecf20Sopenharmony_ci recycle_iov_buf(card, iovb); 21578c2ecf20Sopenharmony_ci return; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* By this point we (hopefully) have a complete SDU without errors. */ 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (NS_PRV_IOVCNT(iovb) == 1) { /* Just a small buffer */ 21638c2ecf20Sopenharmony_ci /* skb points to a small buffer */ 21648c2ecf20Sopenharmony_ci if (!atm_charge(vcc, skb->truesize)) { 21658c2ecf20Sopenharmony_ci push_rxbufs(card, skb); 21668c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 21678c2ecf20Sopenharmony_ci } else { 21688c2ecf20Sopenharmony_ci skb_put(skb, len); 21698c2ecf20Sopenharmony_ci dequeue_sm_buf(card, skb); 21708c2ecf20Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 21718c2ecf20Sopenharmony_ci __net_timestamp(skb); 21728c2ecf20Sopenharmony_ci vcc->push(vcc, skb); 21738c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx); 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci } else if (NS_PRV_IOVCNT(iovb) == 2) { /* One small plus one large buffer */ 21768c2ecf20Sopenharmony_ci struct sk_buff *sb; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci sb = (struct sk_buff *)(iov - 1)->iov_base; 21798c2ecf20Sopenharmony_ci /* skb points to a large buffer */ 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (len <= NS_SMBUFSIZE) { 21828c2ecf20Sopenharmony_ci if (!atm_charge(vcc, sb->truesize)) { 21838c2ecf20Sopenharmony_ci push_rxbufs(card, sb); 21848c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 21858c2ecf20Sopenharmony_ci } else { 21868c2ecf20Sopenharmony_ci skb_put(sb, len); 21878c2ecf20Sopenharmony_ci dequeue_sm_buf(card, sb); 21888c2ecf20Sopenharmony_ci ATM_SKB(sb)->vcc = vcc; 21898c2ecf20Sopenharmony_ci __net_timestamp(sb); 21908c2ecf20Sopenharmony_ci vcc->push(vcc, sb); 21918c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci push_rxbufs(card, skb); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci } else { /* len > NS_SMBUFSIZE, the usual case */ 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if (!atm_charge(vcc, skb->truesize)) { 21998c2ecf20Sopenharmony_ci push_rxbufs(card, skb); 22008c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 22018c2ecf20Sopenharmony_ci } else { 22028c2ecf20Sopenharmony_ci dequeue_lg_buf(card, skb); 22038c2ecf20Sopenharmony_ci skb_push(skb, NS_SMBUFSIZE); 22048c2ecf20Sopenharmony_ci skb_copy_from_linear_data(sb, skb->data, 22058c2ecf20Sopenharmony_ci NS_SMBUFSIZE); 22068c2ecf20Sopenharmony_ci skb_put(skb, len - NS_SMBUFSIZE); 22078c2ecf20Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 22088c2ecf20Sopenharmony_ci __net_timestamp(skb); 22098c2ecf20Sopenharmony_ci vcc->push(vcc, skb); 22108c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx); 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci push_rxbufs(card, sb); 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci } 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci } else { /* Must push a huge buffer */ 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci struct sk_buff *hb, *sb, *lb; 22208c2ecf20Sopenharmony_ci int remaining, tocopy; 22218c2ecf20Sopenharmony_ci int j; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci hb = skb_dequeue(&(card->hbpool.queue)); 22248c2ecf20Sopenharmony_ci if (hb == NULL) { /* No buffers in the queue */ 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci hb = dev_alloc_skb(NS_HBUFSIZE); 22278c2ecf20Sopenharmony_ci if (hb == NULL) { 22288c2ecf20Sopenharmony_ci printk 22298c2ecf20Sopenharmony_ci ("nicstar%d: Out of huge buffers.\n", 22308c2ecf20Sopenharmony_ci card->index); 22318c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 22328c2ecf20Sopenharmony_ci recycle_iovec_rx_bufs(card, 22338c2ecf20Sopenharmony_ci (struct iovec *) 22348c2ecf20Sopenharmony_ci iovb->data, 22358c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 22368c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 22378c2ecf20Sopenharmony_ci recycle_iov_buf(card, iovb); 22388c2ecf20Sopenharmony_ci return; 22398c2ecf20Sopenharmony_ci } else if (card->hbpool.count < card->hbnr.min) { 22408c2ecf20Sopenharmony_ci struct sk_buff *new_hb; 22418c2ecf20Sopenharmony_ci if ((new_hb = 22428c2ecf20Sopenharmony_ci dev_alloc_skb(NS_HBUFSIZE)) != 22438c2ecf20Sopenharmony_ci NULL) { 22448c2ecf20Sopenharmony_ci skb_queue_tail(&card->hbpool. 22458c2ecf20Sopenharmony_ci queue, new_hb); 22468c2ecf20Sopenharmony_ci card->hbpool.count++; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(hb) = BUF_NONE; 22508c2ecf20Sopenharmony_ci } else if (--card->hbpool.count < card->hbnr.min) { 22518c2ecf20Sopenharmony_ci struct sk_buff *new_hb; 22528c2ecf20Sopenharmony_ci if ((new_hb = 22538c2ecf20Sopenharmony_ci dev_alloc_skb(NS_HBUFSIZE)) != NULL) { 22548c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(new_hb) = BUF_NONE; 22558c2ecf20Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, 22568c2ecf20Sopenharmony_ci new_hb); 22578c2ecf20Sopenharmony_ci card->hbpool.count++; 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci if (card->hbpool.count < card->hbnr.min) { 22608c2ecf20Sopenharmony_ci if ((new_hb = 22618c2ecf20Sopenharmony_ci dev_alloc_skb(NS_HBUFSIZE)) != 22628c2ecf20Sopenharmony_ci NULL) { 22638c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(new_hb) = 22648c2ecf20Sopenharmony_ci BUF_NONE; 22658c2ecf20Sopenharmony_ci skb_queue_tail(&card->hbpool. 22668c2ecf20Sopenharmony_ci queue, new_hb); 22678c2ecf20Sopenharmony_ci card->hbpool.count++; 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci iov = (struct iovec *)iovb->data; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci if (!atm_charge(vcc, hb->truesize)) { 22758c2ecf20Sopenharmony_ci recycle_iovec_rx_bufs(card, iov, 22768c2ecf20Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 22778c2ecf20Sopenharmony_ci if (card->hbpool.count < card->hbnr.max) { 22788c2ecf20Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, hb); 22798c2ecf20Sopenharmony_ci card->hbpool.count++; 22808c2ecf20Sopenharmony_ci } else 22818c2ecf20Sopenharmony_ci dev_kfree_skb_any(hb); 22828c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 22838c2ecf20Sopenharmony_ci } else { 22848c2ecf20Sopenharmony_ci /* Copy the small buffer to the huge buffer */ 22858c2ecf20Sopenharmony_ci sb = (struct sk_buff *)iov->iov_base; 22868c2ecf20Sopenharmony_ci skb_copy_from_linear_data(sb, hb->data, 22878c2ecf20Sopenharmony_ci iov->iov_len); 22888c2ecf20Sopenharmony_ci skb_put(hb, iov->iov_len); 22898c2ecf20Sopenharmony_ci remaining = len - iov->iov_len; 22908c2ecf20Sopenharmony_ci iov++; 22918c2ecf20Sopenharmony_ci /* Free the small buffer */ 22928c2ecf20Sopenharmony_ci push_rxbufs(card, sb); 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci /* Copy all large buffers to the huge buffer and free them */ 22958c2ecf20Sopenharmony_ci for (j = 1; j < NS_PRV_IOVCNT(iovb); j++) { 22968c2ecf20Sopenharmony_ci lb = (struct sk_buff *)iov->iov_base; 22978c2ecf20Sopenharmony_ci tocopy = 22988c2ecf20Sopenharmony_ci min_t(int, remaining, iov->iov_len); 22998c2ecf20Sopenharmony_ci skb_copy_from_linear_data(lb, 23008c2ecf20Sopenharmony_ci skb_tail_pointer 23018c2ecf20Sopenharmony_ci (hb), tocopy); 23028c2ecf20Sopenharmony_ci skb_put(hb, tocopy); 23038c2ecf20Sopenharmony_ci iov++; 23048c2ecf20Sopenharmony_ci remaining -= tocopy; 23058c2ecf20Sopenharmony_ci push_rxbufs(card, lb); 23068c2ecf20Sopenharmony_ci } 23078c2ecf20Sopenharmony_ci#ifdef EXTRA_DEBUG 23088c2ecf20Sopenharmony_ci if (remaining != 0 || hb->len != len) 23098c2ecf20Sopenharmony_ci printk 23108c2ecf20Sopenharmony_ci ("nicstar%d: Huge buffer len mismatch.\n", 23118c2ecf20Sopenharmony_ci card->index); 23128c2ecf20Sopenharmony_ci#endif /* EXTRA_DEBUG */ 23138c2ecf20Sopenharmony_ci ATM_SKB(hb)->vcc = vcc; 23148c2ecf20Sopenharmony_ci __net_timestamp(hb); 23158c2ecf20Sopenharmony_ci vcc->push(vcc, hb); 23168c2ecf20Sopenharmony_ci atomic_inc(&vcc->stats->rx); 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci vc->rx_iov = NULL; 23218c2ecf20Sopenharmony_ci recycle_iov_buf(card, iovb); 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic void recycle_rx_buf(ns_dev * card, struct sk_buff *skb) 23278c2ecf20Sopenharmony_ci{ 23288c2ecf20Sopenharmony_ci if (unlikely(NS_PRV_BUFTYPE(skb) == BUF_NONE)) { 23298c2ecf20Sopenharmony_ci printk("nicstar%d: What kind of rx buffer is this?\n", 23308c2ecf20Sopenharmony_ci card->index); 23318c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 23328c2ecf20Sopenharmony_ci } else 23338c2ecf20Sopenharmony_ci push_rxbufs(card, skb); 23348c2ecf20Sopenharmony_ci} 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_cistatic void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count) 23378c2ecf20Sopenharmony_ci{ 23388c2ecf20Sopenharmony_ci while (count-- > 0) 23398c2ecf20Sopenharmony_ci recycle_rx_buf(card, (struct sk_buff *)(iov++)->iov_base); 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_cistatic void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb) 23438c2ecf20Sopenharmony_ci{ 23448c2ecf20Sopenharmony_ci if (card->iovpool.count < card->iovnr.max) { 23458c2ecf20Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, iovb); 23468c2ecf20Sopenharmony_ci card->iovpool.count++; 23478c2ecf20Sopenharmony_ci } else 23488c2ecf20Sopenharmony_ci dev_kfree_skb_any(iovb); 23498c2ecf20Sopenharmony_ci} 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_cistatic void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci skb_unlink(sb, &card->sbpool.queue); 23548c2ecf20Sopenharmony_ci if (card->sbfqc < card->sbnr.init) { 23558c2ecf20Sopenharmony_ci struct sk_buff *new_sb; 23568c2ecf20Sopenharmony_ci if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { 23578c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(new_sb) = BUF_SM; 23588c2ecf20Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, new_sb); 23598c2ecf20Sopenharmony_ci skb_reserve(new_sb, NS_AAL0_HEADER); 23608c2ecf20Sopenharmony_ci push_rxbufs(card, new_sb); 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci if (card->sbfqc < card->sbnr.init) 23648c2ecf20Sopenharmony_ci { 23658c2ecf20Sopenharmony_ci struct sk_buff *new_sb; 23668c2ecf20Sopenharmony_ci if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { 23678c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(new_sb) = BUF_SM; 23688c2ecf20Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, new_sb); 23698c2ecf20Sopenharmony_ci skb_reserve(new_sb, NS_AAL0_HEADER); 23708c2ecf20Sopenharmony_ci push_rxbufs(card, new_sb); 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_cistatic void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb) 23768c2ecf20Sopenharmony_ci{ 23778c2ecf20Sopenharmony_ci skb_unlink(lb, &card->lbpool.queue); 23788c2ecf20Sopenharmony_ci if (card->lbfqc < card->lbnr.init) { 23798c2ecf20Sopenharmony_ci struct sk_buff *new_lb; 23808c2ecf20Sopenharmony_ci if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { 23818c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(new_lb) = BUF_LG; 23828c2ecf20Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, new_lb); 23838c2ecf20Sopenharmony_ci skb_reserve(new_lb, NS_SMBUFSIZE); 23848c2ecf20Sopenharmony_ci push_rxbufs(card, new_lb); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci if (card->lbfqc < card->lbnr.init) 23888c2ecf20Sopenharmony_ci { 23898c2ecf20Sopenharmony_ci struct sk_buff *new_lb; 23908c2ecf20Sopenharmony_ci if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { 23918c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(new_lb) = BUF_LG; 23928c2ecf20Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, new_lb); 23938c2ecf20Sopenharmony_ci skb_reserve(new_lb, NS_SMBUFSIZE); 23948c2ecf20Sopenharmony_ci push_rxbufs(card, new_lb); 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_cistatic int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page) 24008c2ecf20Sopenharmony_ci{ 24018c2ecf20Sopenharmony_ci u32 stat; 24028c2ecf20Sopenharmony_ci ns_dev *card; 24038c2ecf20Sopenharmony_ci int left; 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci left = (int)*pos; 24068c2ecf20Sopenharmony_ci card = (ns_dev *) dev->dev_data; 24078c2ecf20Sopenharmony_ci stat = readl(card->membase + STAT); 24088c2ecf20Sopenharmony_ci if (!left--) 24098c2ecf20Sopenharmony_ci return sprintf(page, "Pool count min init max \n"); 24108c2ecf20Sopenharmony_ci if (!left--) 24118c2ecf20Sopenharmony_ci return sprintf(page, "Small %5d %5d %5d %5d \n", 24128c2ecf20Sopenharmony_ci ns_stat_sfbqc_get(stat), card->sbnr.min, 24138c2ecf20Sopenharmony_ci card->sbnr.init, card->sbnr.max); 24148c2ecf20Sopenharmony_ci if (!left--) 24158c2ecf20Sopenharmony_ci return sprintf(page, "Large %5d %5d %5d %5d \n", 24168c2ecf20Sopenharmony_ci ns_stat_lfbqc_get(stat), card->lbnr.min, 24178c2ecf20Sopenharmony_ci card->lbnr.init, card->lbnr.max); 24188c2ecf20Sopenharmony_ci if (!left--) 24198c2ecf20Sopenharmony_ci return sprintf(page, "Huge %5d %5d %5d %5d \n", 24208c2ecf20Sopenharmony_ci card->hbpool.count, card->hbnr.min, 24218c2ecf20Sopenharmony_ci card->hbnr.init, card->hbnr.max); 24228c2ecf20Sopenharmony_ci if (!left--) 24238c2ecf20Sopenharmony_ci return sprintf(page, "Iovec %5d %5d %5d %5d \n", 24248c2ecf20Sopenharmony_ci card->iovpool.count, card->iovnr.min, 24258c2ecf20Sopenharmony_ci card->iovnr.init, card->iovnr.max); 24268c2ecf20Sopenharmony_ci if (!left--) { 24278c2ecf20Sopenharmony_ci int retval; 24288c2ecf20Sopenharmony_ci retval = 24298c2ecf20Sopenharmony_ci sprintf(page, "Interrupt counter: %u \n", card->intcnt); 24308c2ecf20Sopenharmony_ci card->intcnt = 0; 24318c2ecf20Sopenharmony_ci return retval; 24328c2ecf20Sopenharmony_ci } 24338c2ecf20Sopenharmony_ci#if 0 24348c2ecf20Sopenharmony_ci /* Dump 25.6 Mbps PHY registers */ 24358c2ecf20Sopenharmony_ci /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it 24368c2ecf20Sopenharmony_ci here just in case it's needed for debugging. */ 24378c2ecf20Sopenharmony_ci if (card->max_pcr == ATM_25_PCR && !left--) { 24388c2ecf20Sopenharmony_ci u32 phy_regs[4]; 24398c2ecf20Sopenharmony_ci u32 i; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 24428c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 24438c2ecf20Sopenharmony_ci writel(NS_CMD_READ_UTILITY | 0x00000200 | i, 24448c2ecf20Sopenharmony_ci card->membase + CMD); 24458c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 24468c2ecf20Sopenharmony_ci phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; 24478c2ecf20Sopenharmony_ci } 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", 24508c2ecf20Sopenharmony_ci phy_regs[0], phy_regs[1], phy_regs[2], 24518c2ecf20Sopenharmony_ci phy_regs[3]); 24528c2ecf20Sopenharmony_ci } 24538c2ecf20Sopenharmony_ci#endif /* 0 - Dump 25.6 Mbps PHY registers */ 24548c2ecf20Sopenharmony_ci#if 0 24558c2ecf20Sopenharmony_ci /* Dump TST */ 24568c2ecf20Sopenharmony_ci if (left-- < NS_TST_NUM_ENTRIES) { 24578c2ecf20Sopenharmony_ci if (card->tste2vc[left + 1] == NULL) 24588c2ecf20Sopenharmony_ci return sprintf(page, "%5d - VBR/UBR \n", left + 1); 24598c2ecf20Sopenharmony_ci else 24608c2ecf20Sopenharmony_ci return sprintf(page, "%5d - %d %d \n", left + 1, 24618c2ecf20Sopenharmony_ci card->tste2vc[left + 1]->tx_vcc->vpi, 24628c2ecf20Sopenharmony_ci card->tste2vc[left + 1]->tx_vcc->vci); 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci#endif /* 0 */ 24658c2ecf20Sopenharmony_ci return 0; 24668c2ecf20Sopenharmony_ci} 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_cistatic int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg) 24698c2ecf20Sopenharmony_ci{ 24708c2ecf20Sopenharmony_ci ns_dev *card; 24718c2ecf20Sopenharmony_ci pool_levels pl; 24728c2ecf20Sopenharmony_ci long btype; 24738c2ecf20Sopenharmony_ci unsigned long flags; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci card = dev->dev_data; 24768c2ecf20Sopenharmony_ci switch (cmd) { 24778c2ecf20Sopenharmony_ci case NS_GETPSTAT: 24788c2ecf20Sopenharmony_ci if (get_user 24798c2ecf20Sopenharmony_ci (pl.buftype, &((pool_levels __user *) arg)->buftype)) 24808c2ecf20Sopenharmony_ci return -EFAULT; 24818c2ecf20Sopenharmony_ci switch (pl.buftype) { 24828c2ecf20Sopenharmony_ci case NS_BUFTYPE_SMALL: 24838c2ecf20Sopenharmony_ci pl.count = 24848c2ecf20Sopenharmony_ci ns_stat_sfbqc_get(readl(card->membase + STAT)); 24858c2ecf20Sopenharmony_ci pl.level.min = card->sbnr.min; 24868c2ecf20Sopenharmony_ci pl.level.init = card->sbnr.init; 24878c2ecf20Sopenharmony_ci pl.level.max = card->sbnr.max; 24888c2ecf20Sopenharmony_ci break; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci case NS_BUFTYPE_LARGE: 24918c2ecf20Sopenharmony_ci pl.count = 24928c2ecf20Sopenharmony_ci ns_stat_lfbqc_get(readl(card->membase + STAT)); 24938c2ecf20Sopenharmony_ci pl.level.min = card->lbnr.min; 24948c2ecf20Sopenharmony_ci pl.level.init = card->lbnr.init; 24958c2ecf20Sopenharmony_ci pl.level.max = card->lbnr.max; 24968c2ecf20Sopenharmony_ci break; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci case NS_BUFTYPE_HUGE: 24998c2ecf20Sopenharmony_ci pl.count = card->hbpool.count; 25008c2ecf20Sopenharmony_ci pl.level.min = card->hbnr.min; 25018c2ecf20Sopenharmony_ci pl.level.init = card->hbnr.init; 25028c2ecf20Sopenharmony_ci pl.level.max = card->hbnr.max; 25038c2ecf20Sopenharmony_ci break; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci case NS_BUFTYPE_IOVEC: 25068c2ecf20Sopenharmony_ci pl.count = card->iovpool.count; 25078c2ecf20Sopenharmony_ci pl.level.min = card->iovnr.min; 25088c2ecf20Sopenharmony_ci pl.level.init = card->iovnr.init; 25098c2ecf20Sopenharmony_ci pl.level.max = card->iovnr.max; 25108c2ecf20Sopenharmony_ci break; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci default: 25138c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci } 25168c2ecf20Sopenharmony_ci if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl))) 25178c2ecf20Sopenharmony_ci return (sizeof(pl)); 25188c2ecf20Sopenharmony_ci else 25198c2ecf20Sopenharmony_ci return -EFAULT; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci case NS_SETBUFLEV: 25228c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 25238c2ecf20Sopenharmony_ci return -EPERM; 25248c2ecf20Sopenharmony_ci if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl))) 25258c2ecf20Sopenharmony_ci return -EFAULT; 25268c2ecf20Sopenharmony_ci if (pl.level.min >= pl.level.init 25278c2ecf20Sopenharmony_ci || pl.level.init >= pl.level.max) 25288c2ecf20Sopenharmony_ci return -EINVAL; 25298c2ecf20Sopenharmony_ci if (pl.level.min == 0) 25308c2ecf20Sopenharmony_ci return -EINVAL; 25318c2ecf20Sopenharmony_ci switch (pl.buftype) { 25328c2ecf20Sopenharmony_ci case NS_BUFTYPE_SMALL: 25338c2ecf20Sopenharmony_ci if (pl.level.max > TOP_SB) 25348c2ecf20Sopenharmony_ci return -EINVAL; 25358c2ecf20Sopenharmony_ci card->sbnr.min = pl.level.min; 25368c2ecf20Sopenharmony_ci card->sbnr.init = pl.level.init; 25378c2ecf20Sopenharmony_ci card->sbnr.max = pl.level.max; 25388c2ecf20Sopenharmony_ci break; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci case NS_BUFTYPE_LARGE: 25418c2ecf20Sopenharmony_ci if (pl.level.max > TOP_LB) 25428c2ecf20Sopenharmony_ci return -EINVAL; 25438c2ecf20Sopenharmony_ci card->lbnr.min = pl.level.min; 25448c2ecf20Sopenharmony_ci card->lbnr.init = pl.level.init; 25458c2ecf20Sopenharmony_ci card->lbnr.max = pl.level.max; 25468c2ecf20Sopenharmony_ci break; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci case NS_BUFTYPE_HUGE: 25498c2ecf20Sopenharmony_ci if (pl.level.max > TOP_HB) 25508c2ecf20Sopenharmony_ci return -EINVAL; 25518c2ecf20Sopenharmony_ci card->hbnr.min = pl.level.min; 25528c2ecf20Sopenharmony_ci card->hbnr.init = pl.level.init; 25538c2ecf20Sopenharmony_ci card->hbnr.max = pl.level.max; 25548c2ecf20Sopenharmony_ci break; 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci case NS_BUFTYPE_IOVEC: 25578c2ecf20Sopenharmony_ci if (pl.level.max > TOP_IOVB) 25588c2ecf20Sopenharmony_ci return -EINVAL; 25598c2ecf20Sopenharmony_ci card->iovnr.min = pl.level.min; 25608c2ecf20Sopenharmony_ci card->iovnr.init = pl.level.init; 25618c2ecf20Sopenharmony_ci card->iovnr.max = pl.level.max; 25628c2ecf20Sopenharmony_ci break; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci default: 25658c2ecf20Sopenharmony_ci return -EINVAL; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci } 25688c2ecf20Sopenharmony_ci return 0; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci case NS_ADJBUFLEV: 25718c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 25728c2ecf20Sopenharmony_ci return -EPERM; 25738c2ecf20Sopenharmony_ci btype = (long)arg; /* a long is the same size as a pointer or bigger */ 25748c2ecf20Sopenharmony_ci switch (btype) { 25758c2ecf20Sopenharmony_ci case NS_BUFTYPE_SMALL: 25768c2ecf20Sopenharmony_ci while (card->sbfqc < card->sbnr.init) { 25778c2ecf20Sopenharmony_ci struct sk_buff *sb; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 25808c2ecf20Sopenharmony_ci if (sb == NULL) 25818c2ecf20Sopenharmony_ci return -ENOMEM; 25828c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(sb) = BUF_SM; 25838c2ecf20Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, sb); 25848c2ecf20Sopenharmony_ci skb_reserve(sb, NS_AAL0_HEADER); 25858c2ecf20Sopenharmony_ci push_rxbufs(card, sb); 25868c2ecf20Sopenharmony_ci } 25878c2ecf20Sopenharmony_ci break; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci case NS_BUFTYPE_LARGE: 25908c2ecf20Sopenharmony_ci while (card->lbfqc < card->lbnr.init) { 25918c2ecf20Sopenharmony_ci struct sk_buff *lb; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 25948c2ecf20Sopenharmony_ci if (lb == NULL) 25958c2ecf20Sopenharmony_ci return -ENOMEM; 25968c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(lb) = BUF_LG; 25978c2ecf20Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, lb); 25988c2ecf20Sopenharmony_ci skb_reserve(lb, NS_SMBUFSIZE); 25998c2ecf20Sopenharmony_ci push_rxbufs(card, lb); 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci break; 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci case NS_BUFTYPE_HUGE: 26048c2ecf20Sopenharmony_ci while (card->hbpool.count > card->hbnr.init) { 26058c2ecf20Sopenharmony_ci struct sk_buff *hb; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 26088c2ecf20Sopenharmony_ci hb = skb_dequeue(&card->hbpool.queue); 26098c2ecf20Sopenharmony_ci card->hbpool.count--; 26108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 26118c2ecf20Sopenharmony_ci if (hb == NULL) 26128c2ecf20Sopenharmony_ci printk 26138c2ecf20Sopenharmony_ci ("nicstar%d: huge buffer count inconsistent.\n", 26148c2ecf20Sopenharmony_ci card->index); 26158c2ecf20Sopenharmony_ci else 26168c2ecf20Sopenharmony_ci dev_kfree_skb_any(hb); 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci while (card->hbpool.count < card->hbnr.init) { 26208c2ecf20Sopenharmony_ci struct sk_buff *hb; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 26238c2ecf20Sopenharmony_ci if (hb == NULL) 26248c2ecf20Sopenharmony_ci return -ENOMEM; 26258c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(hb) = BUF_NONE; 26268c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 26278c2ecf20Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, hb); 26288c2ecf20Sopenharmony_ci card->hbpool.count++; 26298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 26308c2ecf20Sopenharmony_ci } 26318c2ecf20Sopenharmony_ci break; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci case NS_BUFTYPE_IOVEC: 26348c2ecf20Sopenharmony_ci while (card->iovpool.count > card->iovnr.init) { 26358c2ecf20Sopenharmony_ci struct sk_buff *iovb; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 26388c2ecf20Sopenharmony_ci iovb = skb_dequeue(&card->iovpool.queue); 26398c2ecf20Sopenharmony_ci card->iovpool.count--; 26408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 26418c2ecf20Sopenharmony_ci if (iovb == NULL) 26428c2ecf20Sopenharmony_ci printk 26438c2ecf20Sopenharmony_ci ("nicstar%d: iovec buffer count inconsistent.\n", 26448c2ecf20Sopenharmony_ci card->index); 26458c2ecf20Sopenharmony_ci else 26468c2ecf20Sopenharmony_ci dev_kfree_skb_any(iovb); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci } 26498c2ecf20Sopenharmony_ci while (card->iovpool.count < card->iovnr.init) { 26508c2ecf20Sopenharmony_ci struct sk_buff *iovb; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); 26538c2ecf20Sopenharmony_ci if (iovb == NULL) 26548c2ecf20Sopenharmony_ci return -ENOMEM; 26558c2ecf20Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 26568c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 26578c2ecf20Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, iovb); 26588c2ecf20Sopenharmony_ci card->iovpool.count++; 26598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci break; 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci default: 26648c2ecf20Sopenharmony_ci return -EINVAL; 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci return 0; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci default: 26708c2ecf20Sopenharmony_ci if (dev->phy && dev->phy->ioctl) { 26718c2ecf20Sopenharmony_ci return dev->phy->ioctl(dev, cmd, arg); 26728c2ecf20Sopenharmony_ci } else { 26738c2ecf20Sopenharmony_ci printk("nicstar%d: %s == NULL \n", card->index, 26748c2ecf20Sopenharmony_ci dev->phy ? "dev->phy->ioctl" : "dev->phy"); 26758c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 26768c2ecf20Sopenharmony_ci } 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci} 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci#ifdef EXTRA_DEBUG 26818c2ecf20Sopenharmony_cistatic void which_list(ns_dev * card, struct sk_buff *skb) 26828c2ecf20Sopenharmony_ci{ 26838c2ecf20Sopenharmony_ci printk("skb buf_type: 0x%08x\n", NS_PRV_BUFTYPE(skb)); 26848c2ecf20Sopenharmony_ci} 26858c2ecf20Sopenharmony_ci#endif /* EXTRA_DEBUG */ 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_cistatic void ns_poll(struct timer_list *unused) 26888c2ecf20Sopenharmony_ci{ 26898c2ecf20Sopenharmony_ci int i; 26908c2ecf20Sopenharmony_ci ns_dev *card; 26918c2ecf20Sopenharmony_ci unsigned long flags; 26928c2ecf20Sopenharmony_ci u32 stat_r, stat_w; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci PRINTK("nicstar: Entering ns_poll().\n"); 26958c2ecf20Sopenharmony_ci for (i = 0; i < num_cards; i++) { 26968c2ecf20Sopenharmony_ci card = cards[i]; 26978c2ecf20Sopenharmony_ci if (!spin_trylock_irqsave(&card->int_lock, flags)) { 26988c2ecf20Sopenharmony_ci /* Probably it isn't worth spinning */ 26998c2ecf20Sopenharmony_ci continue; 27008c2ecf20Sopenharmony_ci } 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci stat_w = 0; 27038c2ecf20Sopenharmony_ci stat_r = readl(card->membase + STAT); 27048c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_TSIF) 27058c2ecf20Sopenharmony_ci stat_w |= NS_STAT_TSIF; 27068c2ecf20Sopenharmony_ci if (stat_r & NS_STAT_EOPDU) 27078c2ecf20Sopenharmony_ci stat_w |= NS_STAT_EOPDU; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci process_tsq(card); 27108c2ecf20Sopenharmony_ci process_rsq(card); 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci writel(stat_w, card->membase + STAT); 27138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); 27168c2ecf20Sopenharmony_ci PRINTK("nicstar: Leaving ns_poll().\n"); 27178c2ecf20Sopenharmony_ci} 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_cistatic void ns_phy_put(struct atm_dev *dev, unsigned char value, 27208c2ecf20Sopenharmony_ci unsigned long addr) 27218c2ecf20Sopenharmony_ci{ 27228c2ecf20Sopenharmony_ci ns_dev *card; 27238c2ecf20Sopenharmony_ci unsigned long flags; 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci card = dev->dev_data; 27268c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 27278c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 27288c2ecf20Sopenharmony_ci writel((u32) value, card->membase + DR0); 27298c2ecf20Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF), 27308c2ecf20Sopenharmony_ci card->membase + CMD); 27318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 27328c2ecf20Sopenharmony_ci} 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_cistatic unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr) 27358c2ecf20Sopenharmony_ci{ 27368c2ecf20Sopenharmony_ci ns_dev *card; 27378c2ecf20Sopenharmony_ci unsigned long flags; 27388c2ecf20Sopenharmony_ci u32 data; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci card = dev->dev_data; 27418c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 27428c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 27438c2ecf20Sopenharmony_ci writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF), 27448c2ecf20Sopenharmony_ci card->membase + CMD); 27458c2ecf20Sopenharmony_ci while (CMD_BUSY(card)) ; 27468c2ecf20Sopenharmony_ci data = readl(card->membase + DR0) & 0x000000FF; 27478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 27488c2ecf20Sopenharmony_ci return (unsigned char)data; 27498c2ecf20Sopenharmony_ci} 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_cimodule_init(nicstar_init); 27528c2ecf20Sopenharmony_cimodule_exit(nicstar_cleanup); 2753