19c54004eSDavid Woodhouse /* 29c54004eSDavid Woodhouse * Driver for the Solos PCI ADSL2+ card, designed to support Linux by 39c54004eSDavid Woodhouse * Traverse Technologies -- http://www.traverse.com.au/ 49c54004eSDavid Woodhouse * Xrio Limited -- http://www.xrio.com/ 59c54004eSDavid Woodhouse * 69c54004eSDavid Woodhouse * 79c54004eSDavid Woodhouse * Copyright © 2008 Traverse Technologies 89c54004eSDavid Woodhouse * Copyright © 2008 Intel Corporation 99c54004eSDavid Woodhouse * 109c54004eSDavid Woodhouse * Authors: Nathan Williams <nathan@traverse.com.au> 119c54004eSDavid Woodhouse * David Woodhouse <dwmw2@infradead.org> 127c4015bdSSimon Farnsworth * Treker Chen <treker@xrio.com> 139c54004eSDavid Woodhouse * 149c54004eSDavid Woodhouse * This program is free software; you can redistribute it and/or 159c54004eSDavid Woodhouse * modify it under the terms of the GNU General Public License 169c54004eSDavid Woodhouse * version 2, as published by the Free Software Foundation. 179c54004eSDavid Woodhouse * 189c54004eSDavid Woodhouse * This program is distributed in the hope that it will be useful, 199c54004eSDavid Woodhouse * but WITHOUT ANY WARRANTY; without even the implied warranty of 209c54004eSDavid Woodhouse * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 219c54004eSDavid Woodhouse * GNU General Public License for more details. 229c54004eSDavid Woodhouse */ 239c54004eSDavid Woodhouse 249c54004eSDavid Woodhouse #define DEBUG 259c54004eSDavid Woodhouse #define VERBOSE_DEBUG 269c54004eSDavid Woodhouse 279c54004eSDavid Woodhouse #include <linux/interrupt.h> 289c54004eSDavid Woodhouse #include <linux/module.h> 299c54004eSDavid Woodhouse #include <linux/kernel.h> 309c54004eSDavid Woodhouse #include <linux/errno.h> 319c54004eSDavid Woodhouse #include <linux/ioport.h> 329c54004eSDavid Woodhouse #include <linux/types.h> 339c54004eSDavid Woodhouse #include <linux/pci.h> 349c54004eSDavid Woodhouse #include <linux/atm.h> 359c54004eSDavid Woodhouse #include <linux/atmdev.h> 369c54004eSDavid Woodhouse #include <linux/skbuff.h> 379c54004eSDavid Woodhouse #include <linux/sysfs.h> 389c54004eSDavid Woodhouse #include <linux/device.h> 399c54004eSDavid Woodhouse #include <linux/kobject.h> 407c4015bdSSimon Farnsworth #include <linux/firmware.h> 4101e2ffacSDavid Woodhouse #include <linux/ctype.h> 4201e2ffacSDavid Woodhouse #include <linux/swab.h> 435a0e3ad6STejun Heo #include <linux/slab.h> 449c54004eSDavid Woodhouse 4513af8164SNathan Williams #define VERSION "1.04" 4613af8164SNathan Williams #define DRIVER_VERSION 0x01 479c54004eSDavid Woodhouse #define PTAG "solos-pci" 489c54004eSDavid Woodhouse 499c54004eSDavid Woodhouse #define CONFIG_RAM_SIZE 128 509c54004eSDavid Woodhouse #define FLAGS_ADDR 0x7C 519c54004eSDavid Woodhouse #define IRQ_EN_ADDR 0x78 529c54004eSDavid Woodhouse #define FPGA_VER 0x74 539c54004eSDavid Woodhouse #define IRQ_CLEAR 0x70 547c4015bdSSimon Farnsworth #define WRITE_FLASH 0x6C 557c4015bdSSimon Farnsworth #define PORTS 0x68 567c4015bdSSimon Farnsworth #define FLASH_BLOCK 0x64 577c4015bdSSimon Farnsworth #define FLASH_BUSY 0x60 587c4015bdSSimon Farnsworth #define FPGA_MODE 0x5C 597c4015bdSSimon Farnsworth #define FLASH_MODE 0x58 60f9baad02SNathan Williams #define GPIO_STATUS 0x54 6113af8164SNathan Williams #define DRIVER_VER 0x50 6290937231SDavid Woodhouse #define TX_DMA_ADDR(port) (0x40 + (4 * (port))) 6390937231SDavid Woodhouse #define RX_DMA_ADDR(port) (0x30 + (4 * (port))) 649c54004eSDavid Woodhouse 659c54004eSDavid Woodhouse #define DATA_RAM_SIZE 32768 664dbedf43SNathan Williams #define BUF_SIZE 2048 674dbedf43SNathan Williams #define OLD_BUF_SIZE 4096 /* For FPGA versions <= 2*/ 6813af8164SNathan Williams /* Old boards use ATMEL AD45DB161D flash */ 6913af8164SNathan Williams #define ATMEL_FPGA_PAGE 528 /* FPGA flash page size*/ 7013af8164SNathan Williams #define ATMEL_SOLOS_PAGE 512 /* Solos flash page size*/ 7113af8164SNathan Williams #define ATMEL_FPGA_BLOCK (ATMEL_FPGA_PAGE * 8) /* FPGA block size*/ 7213af8164SNathan Williams #define ATMEL_SOLOS_BLOCK (ATMEL_SOLOS_PAGE * 8) /* Solos block size*/ 7313af8164SNathan Williams /* Current boards use M25P/M25PE SPI flash */ 7413af8164SNathan Williams #define SPI_FLASH_BLOCK (256 * 64) 759c54004eSDavid Woodhouse 764dbedf43SNathan Williams #define RX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2) 774dbedf43SNathan Williams #define TX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2 + (card->buffer_size)) 784dbedf43SNathan Williams #define FLASH_BUF ((card->buffers) + 4*(card->buffer_size)*2) 799c54004eSDavid Woodhouse 80eaf83e39SDavid Woodhouse #define RX_DMA_SIZE 2048 81eaf83e39SDavid Woodhouse 824dbedf43SNathan Williams #define FPGA_VERSION(a,b) (((a) << 8) + (b)) 834dbedf43SNathan Williams #define LEGACY_BUFFERS 2 844dbedf43SNathan Williams #define DMA_SUPPORTED 4 854dbedf43SNathan Williams 86cc3657e1SDavid Woodhouse static int reset = 0; 879c54004eSDavid Woodhouse static int atmdebug = 0; 887c4015bdSSimon Farnsworth static int firmware_upgrade = 0; 897c4015bdSSimon Farnsworth static int fpga_upgrade = 0; 904dbedf43SNathan Williams static int db_firmware_upgrade = 0; 914dbedf43SNathan Williams static int db_fpga_upgrade = 0; 929c54004eSDavid Woodhouse 939c54004eSDavid Woodhouse struct pkt_hdr { 949c54004eSDavid Woodhouse __le16 size; 959c54004eSDavid Woodhouse __le16 vpi; 969c54004eSDavid Woodhouse __le16 vci; 979c54004eSDavid Woodhouse __le16 type; 989c54004eSDavid Woodhouse }; 999c54004eSDavid Woodhouse 10090937231SDavid Woodhouse struct solos_skb_cb { 10190937231SDavid Woodhouse struct atm_vcc *vcc; 10290937231SDavid Woodhouse uint32_t dma_addr; 10390937231SDavid Woodhouse }; 10490937231SDavid Woodhouse 10590937231SDavid Woodhouse 10690937231SDavid Woodhouse #define SKB_CB(skb) ((struct solos_skb_cb *)skb->cb) 10790937231SDavid Woodhouse 1089c54004eSDavid Woodhouse #define PKT_DATA 0 1099c54004eSDavid Woodhouse #define PKT_COMMAND 1 1109c54004eSDavid Woodhouse #define PKT_POPEN 3 1119c54004eSDavid Woodhouse #define PKT_PCLOSE 4 11287ebb186SDavid Woodhouse #define PKT_STATUS 5 1139c54004eSDavid Woodhouse 1149c54004eSDavid Woodhouse struct solos_card { 1159c54004eSDavid Woodhouse void __iomem *config_regs; 1169c54004eSDavid Woodhouse void __iomem *buffers; 1179c54004eSDavid Woodhouse int nr_ports; 118f69e4170SDavid Woodhouse int tx_mask; 1199c54004eSDavid Woodhouse struct pci_dev *dev; 1209c54004eSDavid Woodhouse struct atm_dev *atmdev[4]; 1219c54004eSDavid Woodhouse struct tasklet_struct tlet; 1229c54004eSDavid Woodhouse spinlock_t tx_lock; 1239c54004eSDavid Woodhouse spinlock_t tx_queue_lock; 1249c54004eSDavid Woodhouse spinlock_t cli_queue_lock; 12501e2ffacSDavid Woodhouse spinlock_t param_queue_lock; 12601e2ffacSDavid Woodhouse struct list_head param_queue; 1279c54004eSDavid Woodhouse struct sk_buff_head tx_queue[4]; 1289c54004eSDavid Woodhouse struct sk_buff_head cli_queue[4]; 12990937231SDavid Woodhouse struct sk_buff *tx_skb[4]; 13090937231SDavid Woodhouse struct sk_buff *rx_skb[4]; 131152a2a8bSDavid Woodhouse unsigned char *dma_bounce; 13201e2ffacSDavid Woodhouse wait_queue_head_t param_wq; 133fa755b9fSDavid Woodhouse wait_queue_head_t fw_wq; 13490937231SDavid Woodhouse int using_dma; 135152a2a8bSDavid Woodhouse int dma_alignment; 1364dbedf43SNathan Williams int fpga_version; 1374dbedf43SNathan Williams int buffer_size; 13813af8164SNathan Williams int atmel_flash; 1399c54004eSDavid Woodhouse }; 1409c54004eSDavid Woodhouse 14101e2ffacSDavid Woodhouse 14201e2ffacSDavid Woodhouse struct solos_param { 14301e2ffacSDavid Woodhouse struct list_head list; 14401e2ffacSDavid Woodhouse pid_t pid; 14501e2ffacSDavid Woodhouse int port; 14601e2ffacSDavid Woodhouse struct sk_buff *response; 1479c54004eSDavid Woodhouse }; 1489c54004eSDavid Woodhouse 1499c54004eSDavid Woodhouse #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) 1509c54004eSDavid Woodhouse 1519c54004eSDavid Woodhouse MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>"); 1529c54004eSDavid Woodhouse MODULE_DESCRIPTION("Solos PCI driver"); 1539c54004eSDavid Woodhouse MODULE_VERSION(VERSION); 1549c54004eSDavid Woodhouse MODULE_LICENSE("GPL"); 1559fca79d6SBen Hutchings MODULE_FIRMWARE("solos-FPGA.bin"); 1569fca79d6SBen Hutchings MODULE_FIRMWARE("solos-Firmware.bin"); 1579fca79d6SBen Hutchings MODULE_FIRMWARE("solos-db-FPGA.bin"); 158cc3657e1SDavid Woodhouse MODULE_PARM_DESC(reset, "Reset Solos chips on startup"); 1599c54004eSDavid Woodhouse MODULE_PARM_DESC(atmdebug, "Print ATM data"); 1607c4015bdSSimon Farnsworth MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade"); 1617c4015bdSSimon Farnsworth MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade"); 1624dbedf43SNathan Williams MODULE_PARM_DESC(db_firmware_upgrade, "Initiate daughter board Solos firmware upgrade"); 1634dbedf43SNathan Williams MODULE_PARM_DESC(db_fpga_upgrade, "Initiate daughter board FPGA upgrade"); 164cc3657e1SDavid Woodhouse module_param(reset, int, 0444); 1654306cad6SSimon Farnsworth module_param(atmdebug, int, 0644); 1667c4015bdSSimon Farnsworth module_param(firmware_upgrade, int, 0444); 1677c4015bdSSimon Farnsworth module_param(fpga_upgrade, int, 0444); 1684dbedf43SNathan Williams module_param(db_firmware_upgrade, int, 0444); 1694dbedf43SNathan Williams module_param(db_fpga_upgrade, int, 0444); 1709c54004eSDavid Woodhouse 1719c54004eSDavid Woodhouse static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, 1729c54004eSDavid Woodhouse struct atm_vcc *vcc); 17335c2221bSDavid Woodhouse static uint32_t fpga_tx(struct solos_card *); 1749c54004eSDavid Woodhouse static irqreturn_t solos_irq(int irq, void *dev_id); 1759c54004eSDavid Woodhouse static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); 176d9ca676bSDan Williams static int atm_init(struct solos_card *, struct device *); 1779c54004eSDavid Woodhouse static void atm_remove(struct solos_card *); 1789c54004eSDavid Woodhouse static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); 1799c54004eSDavid Woodhouse static void solos_bh(unsigned long); 1809c54004eSDavid Woodhouse static int print_buffer(struct sk_buff *buf); 1819c54004eSDavid Woodhouse 1829c54004eSDavid Woodhouse static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb) 1839c54004eSDavid Woodhouse { 1849c54004eSDavid Woodhouse if (vcc->pop) 1859c54004eSDavid Woodhouse vcc->pop(vcc, skb); 1869c54004eSDavid Woodhouse else 1879c54004eSDavid Woodhouse dev_kfree_skb_any(skb); 1889c54004eSDavid Woodhouse } 1899c54004eSDavid Woodhouse 19001e2ffacSDavid Woodhouse static ssize_t solos_param_show(struct device *dev, struct device_attribute *attr, 19101e2ffacSDavid Woodhouse char *buf) 19201e2ffacSDavid Woodhouse { 19301e2ffacSDavid Woodhouse struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); 19401e2ffacSDavid Woodhouse struct solos_card *card = atmdev->dev_data; 19501e2ffacSDavid Woodhouse struct solos_param prm; 19601e2ffacSDavid Woodhouse struct sk_buff *skb; 19701e2ffacSDavid Woodhouse struct pkt_hdr *header; 19801e2ffacSDavid Woodhouse int buflen; 19901e2ffacSDavid Woodhouse 20001e2ffacSDavid Woodhouse buflen = strlen(attr->attr.name) + 10; 20101e2ffacSDavid Woodhouse 2023456b221SDavid Woodhouse skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL); 20301e2ffacSDavid Woodhouse if (!skb) { 20401e2ffacSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n"); 20501e2ffacSDavid Woodhouse return -ENOMEM; 20601e2ffacSDavid Woodhouse } 20701e2ffacSDavid Woodhouse 20801e2ffacSDavid Woodhouse header = (void *)skb_put(skb, sizeof(*header)); 20901e2ffacSDavid Woodhouse 21001e2ffacSDavid Woodhouse buflen = snprintf((void *)&header[1], buflen - 1, 21101e2ffacSDavid Woodhouse "L%05d\n%s\n", current->pid, attr->attr.name); 21201e2ffacSDavid Woodhouse skb_put(skb, buflen); 21301e2ffacSDavid Woodhouse 21401e2ffacSDavid Woodhouse header->size = cpu_to_le16(buflen); 21501e2ffacSDavid Woodhouse header->vpi = cpu_to_le16(0); 21601e2ffacSDavid Woodhouse header->vci = cpu_to_le16(0); 21701e2ffacSDavid Woodhouse header->type = cpu_to_le16(PKT_COMMAND); 21801e2ffacSDavid Woodhouse 21901e2ffacSDavid Woodhouse prm.pid = current->pid; 22001e2ffacSDavid Woodhouse prm.response = NULL; 22101e2ffacSDavid Woodhouse prm.port = SOLOS_CHAN(atmdev); 22201e2ffacSDavid Woodhouse 22301e2ffacSDavid Woodhouse spin_lock_irq(&card->param_queue_lock); 22401e2ffacSDavid Woodhouse list_add(&prm.list, &card->param_queue); 22501e2ffacSDavid Woodhouse spin_unlock_irq(&card->param_queue_lock); 22601e2ffacSDavid Woodhouse 22701e2ffacSDavid Woodhouse fpga_queue(card, prm.port, skb, NULL); 22801e2ffacSDavid Woodhouse 22901e2ffacSDavid Woodhouse wait_event_timeout(card->param_wq, prm.response, 5 * HZ); 23001e2ffacSDavid Woodhouse 23101e2ffacSDavid Woodhouse spin_lock_irq(&card->param_queue_lock); 23201e2ffacSDavid Woodhouse list_del(&prm.list); 23301e2ffacSDavid Woodhouse spin_unlock_irq(&card->param_queue_lock); 23401e2ffacSDavid Woodhouse 23501e2ffacSDavid Woodhouse if (!prm.response) 23601e2ffacSDavid Woodhouse return -EIO; 23701e2ffacSDavid Woodhouse 23801e2ffacSDavid Woodhouse buflen = prm.response->len; 23901e2ffacSDavid Woodhouse memcpy(buf, prm.response->data, buflen); 24001e2ffacSDavid Woodhouse kfree_skb(prm.response); 24101e2ffacSDavid Woodhouse 24201e2ffacSDavid Woodhouse return buflen; 24301e2ffacSDavid Woodhouse } 24401e2ffacSDavid Woodhouse 24501e2ffacSDavid Woodhouse static ssize_t solos_param_store(struct device *dev, struct device_attribute *attr, 24601e2ffacSDavid Woodhouse const char *buf, size_t count) 24701e2ffacSDavid Woodhouse { 24801e2ffacSDavid Woodhouse struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); 24901e2ffacSDavid Woodhouse struct solos_card *card = atmdev->dev_data; 25001e2ffacSDavid Woodhouse struct solos_param prm; 25101e2ffacSDavid Woodhouse struct sk_buff *skb; 25201e2ffacSDavid Woodhouse struct pkt_hdr *header; 25301e2ffacSDavid Woodhouse int buflen; 25401e2ffacSDavid Woodhouse ssize_t ret; 25501e2ffacSDavid Woodhouse 25601e2ffacSDavid Woodhouse buflen = strlen(attr->attr.name) + 11 + count; 25701e2ffacSDavid Woodhouse 2583456b221SDavid Woodhouse skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL); 25901e2ffacSDavid Woodhouse if (!skb) { 26001e2ffacSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n"); 26101e2ffacSDavid Woodhouse return -ENOMEM; 26201e2ffacSDavid Woodhouse } 26301e2ffacSDavid Woodhouse 26401e2ffacSDavid Woodhouse header = (void *)skb_put(skb, sizeof(*header)); 26501e2ffacSDavid Woodhouse 26601e2ffacSDavid Woodhouse buflen = snprintf((void *)&header[1], buflen - 1, 26701e2ffacSDavid Woodhouse "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf); 26801e2ffacSDavid Woodhouse 26901e2ffacSDavid Woodhouse skb_put(skb, buflen); 27001e2ffacSDavid Woodhouse header->size = cpu_to_le16(buflen); 27101e2ffacSDavid Woodhouse header->vpi = cpu_to_le16(0); 27201e2ffacSDavid Woodhouse header->vci = cpu_to_le16(0); 27301e2ffacSDavid Woodhouse header->type = cpu_to_le16(PKT_COMMAND); 27401e2ffacSDavid Woodhouse 27501e2ffacSDavid Woodhouse prm.pid = current->pid; 27601e2ffacSDavid Woodhouse prm.response = NULL; 27701e2ffacSDavid Woodhouse prm.port = SOLOS_CHAN(atmdev); 27801e2ffacSDavid Woodhouse 27901e2ffacSDavid Woodhouse spin_lock_irq(&card->param_queue_lock); 28001e2ffacSDavid Woodhouse list_add(&prm.list, &card->param_queue); 28101e2ffacSDavid Woodhouse spin_unlock_irq(&card->param_queue_lock); 28201e2ffacSDavid Woodhouse 28301e2ffacSDavid Woodhouse fpga_queue(card, prm.port, skb, NULL); 28401e2ffacSDavid Woodhouse 28501e2ffacSDavid Woodhouse wait_event_timeout(card->param_wq, prm.response, 5 * HZ); 28601e2ffacSDavid Woodhouse 28701e2ffacSDavid Woodhouse spin_lock_irq(&card->param_queue_lock); 28801e2ffacSDavid Woodhouse list_del(&prm.list); 28901e2ffacSDavid Woodhouse spin_unlock_irq(&card->param_queue_lock); 29001e2ffacSDavid Woodhouse 29101e2ffacSDavid Woodhouse skb = prm.response; 29201e2ffacSDavid Woodhouse 29301e2ffacSDavid Woodhouse if (!skb) 29401e2ffacSDavid Woodhouse return -EIO; 29501e2ffacSDavid Woodhouse 29601e2ffacSDavid Woodhouse buflen = skb->len; 29701e2ffacSDavid Woodhouse 29801e2ffacSDavid Woodhouse /* Sometimes it has a newline, sometimes it doesn't. */ 29901e2ffacSDavid Woodhouse if (skb->data[buflen - 1] == '\n') 30001e2ffacSDavid Woodhouse buflen--; 30101e2ffacSDavid Woodhouse 30201e2ffacSDavid Woodhouse if (buflen == 2 && !strncmp(skb->data, "OK", 2)) 30301e2ffacSDavid Woodhouse ret = count; 30401e2ffacSDavid Woodhouse else if (buflen == 5 && !strncmp(skb->data, "ERROR", 5)) 30501e2ffacSDavid Woodhouse ret = -EIO; 30601e2ffacSDavid Woodhouse else { 30701e2ffacSDavid Woodhouse /* We know we have enough space allocated for this; we allocated 30801e2ffacSDavid Woodhouse it ourselves */ 30901e2ffacSDavid Woodhouse skb->data[buflen] = 0; 31001e2ffacSDavid Woodhouse 31101e2ffacSDavid Woodhouse dev_warn(&card->dev->dev, "Unexpected parameter response: '%s'\n", 31201e2ffacSDavid Woodhouse skb->data); 31301e2ffacSDavid Woodhouse ret = -EIO; 31401e2ffacSDavid Woodhouse } 31501e2ffacSDavid Woodhouse kfree_skb(skb); 31601e2ffacSDavid Woodhouse 31701e2ffacSDavid Woodhouse return ret; 31801e2ffacSDavid Woodhouse } 31901e2ffacSDavid Woodhouse 32087ebb186SDavid Woodhouse static char *next_string(struct sk_buff *skb) 32187ebb186SDavid Woodhouse { 32287ebb186SDavid Woodhouse int i = 0; 32387ebb186SDavid Woodhouse char *this = skb->data; 32487ebb186SDavid Woodhouse 325c6428e52SDavid Woodhouse for (i = 0; i < skb->len; i++) { 32687ebb186SDavid Woodhouse if (this[i] == '\n') { 32787ebb186SDavid Woodhouse this[i] = 0; 328c6428e52SDavid Woodhouse skb_pull(skb, i + 1); 32987ebb186SDavid Woodhouse return this; 33087ebb186SDavid Woodhouse } 331c6428e52SDavid Woodhouse if (!isprint(this[i])) 332c6428e52SDavid Woodhouse return NULL; 33387ebb186SDavid Woodhouse } 33487ebb186SDavid Woodhouse return NULL; 33587ebb186SDavid Woodhouse } 33687ebb186SDavid Woodhouse 33787ebb186SDavid Woodhouse /* 33887ebb186SDavid Woodhouse * Status packet has fields separated by \n, starting with a version number 33987ebb186SDavid Woodhouse * for the information therein. Fields are.... 34087ebb186SDavid Woodhouse * 34187ebb186SDavid Woodhouse * packet version 34287ebb186SDavid Woodhouse * RxBitRate (version >= 1) 343f87b2ed2SDavid Woodhouse * TxBitRate (version >= 1) 34487ebb186SDavid Woodhouse * State (version >= 1) 345f87b2ed2SDavid Woodhouse * LocalSNRMargin (version >= 1) 346f87b2ed2SDavid Woodhouse * LocalLineAttn (version >= 1) 34787ebb186SDavid Woodhouse */ 34887ebb186SDavid Woodhouse static int process_status(struct solos_card *card, int port, struct sk_buff *skb) 34987ebb186SDavid Woodhouse { 350f87b2ed2SDavid Woodhouse char *str, *end, *state_str, *snr, *attn; 351f87b2ed2SDavid Woodhouse int ver, rate_up, rate_down; 35287ebb186SDavid Woodhouse 35387ebb186SDavid Woodhouse if (!card->atmdev[port]) 35487ebb186SDavid Woodhouse return -ENODEV; 35587ebb186SDavid Woodhouse 35687ebb186SDavid Woodhouse str = next_string(skb); 35787ebb186SDavid Woodhouse if (!str) 35887ebb186SDavid Woodhouse return -EIO; 35987ebb186SDavid Woodhouse 36087ebb186SDavid Woodhouse ver = simple_strtol(str, NULL, 10); 36187ebb186SDavid Woodhouse if (ver < 1) { 36287ebb186SDavid Woodhouse dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n", 36387ebb186SDavid Woodhouse ver); 36487ebb186SDavid Woodhouse return -EIO; 36587ebb186SDavid Woodhouse } 36687ebb186SDavid Woodhouse 36787ebb186SDavid Woodhouse str = next_string(skb); 368c6428e52SDavid Woodhouse if (!str) 369c6428e52SDavid Woodhouse return -EIO; 37095852f48SDavid Woodhouse if (!strcmp(str, "ERROR")) { 37195852f48SDavid Woodhouse dev_dbg(&card->dev->dev, "Status packet indicated Solos error on port %d (starting up?)\n", 37295852f48SDavid Woodhouse port); 37395852f48SDavid Woodhouse return 0; 37495852f48SDavid Woodhouse } 37595852f48SDavid Woodhouse 376f87b2ed2SDavid Woodhouse rate_down = simple_strtol(str, &end, 10); 37787ebb186SDavid Woodhouse if (*end) 37887ebb186SDavid Woodhouse return -EIO; 37987ebb186SDavid Woodhouse 38087ebb186SDavid Woodhouse str = next_string(skb); 381c6428e52SDavid Woodhouse if (!str) 382c6428e52SDavid Woodhouse return -EIO; 383f87b2ed2SDavid Woodhouse rate_up = simple_strtol(str, &end, 10); 38487ebb186SDavid Woodhouse if (*end) 38587ebb186SDavid Woodhouse return -EIO; 38687ebb186SDavid Woodhouse 387af780656SDavid Woodhouse state_str = next_string(skb); 388c6428e52SDavid Woodhouse if (!state_str) 389c6428e52SDavid Woodhouse return -EIO; 39087ebb186SDavid Woodhouse 391f87b2ed2SDavid Woodhouse /* Anything but 'Showtime' is down */ 392f87b2ed2SDavid Woodhouse if (strcmp(state_str, "Showtime")) { 39349d49106SKarl Hiramoto atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_LOST); 39495852f48SDavid Woodhouse dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str); 395f87b2ed2SDavid Woodhouse return 0; 396f87b2ed2SDavid Woodhouse } 397af780656SDavid Woodhouse 398c6428e52SDavid Woodhouse snr = next_string(skb); 3996cf5767cSJulia Lawall if (!snr) 400c6428e52SDavid Woodhouse return -EIO; 401c6428e52SDavid Woodhouse attn = next_string(skb); 402c6428e52SDavid Woodhouse if (!attn) 403c6428e52SDavid Woodhouse return -EIO; 404c6428e52SDavid Woodhouse 40595852f48SDavid Woodhouse dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n", 406c6428e52SDavid Woodhouse port, state_str, rate_down/1000, rate_up/1000, 407c6428e52SDavid Woodhouse snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn); 408f87b2ed2SDavid Woodhouse 409c6428e52SDavid Woodhouse card->atmdev[port]->link_rate = rate_down / 424; 41049d49106SKarl Hiramoto atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_FOUND); 41187ebb186SDavid Woodhouse 41287ebb186SDavid Woodhouse return 0; 41387ebb186SDavid Woodhouse } 41487ebb186SDavid Woodhouse 41501e2ffacSDavid Woodhouse static int process_command(struct solos_card *card, int port, struct sk_buff *skb) 41601e2ffacSDavid Woodhouse { 41701e2ffacSDavid Woodhouse struct solos_param *prm; 41801e2ffacSDavid Woodhouse unsigned long flags; 41901e2ffacSDavid Woodhouse int cmdpid; 42001e2ffacSDavid Woodhouse int found = 0; 42101e2ffacSDavid Woodhouse 42201e2ffacSDavid Woodhouse if (skb->len < 7) 42301e2ffacSDavid Woodhouse return 0; 42401e2ffacSDavid Woodhouse 42501e2ffacSDavid Woodhouse if (skb->data[0] != 'L' || !isdigit(skb->data[1]) || 42601e2ffacSDavid Woodhouse !isdigit(skb->data[2]) || !isdigit(skb->data[3]) || 42701e2ffacSDavid Woodhouse !isdigit(skb->data[4]) || !isdigit(skb->data[5]) || 42801e2ffacSDavid Woodhouse skb->data[6] != '\n') 42901e2ffacSDavid Woodhouse return 0; 43001e2ffacSDavid Woodhouse 43101e2ffacSDavid Woodhouse cmdpid = simple_strtol(&skb->data[1], NULL, 10); 43201e2ffacSDavid Woodhouse 43301e2ffacSDavid Woodhouse spin_lock_irqsave(&card->param_queue_lock, flags); 43401e2ffacSDavid Woodhouse list_for_each_entry(prm, &card->param_queue, list) { 43501e2ffacSDavid Woodhouse if (prm->port == port && prm->pid == cmdpid) { 43601e2ffacSDavid Woodhouse prm->response = skb; 43701e2ffacSDavid Woodhouse skb_pull(skb, 7); 43801e2ffacSDavid Woodhouse wake_up(&card->param_wq); 43901e2ffacSDavid Woodhouse found = 1; 44001e2ffacSDavid Woodhouse break; 44101e2ffacSDavid Woodhouse } 44201e2ffacSDavid Woodhouse } 44301e2ffacSDavid Woodhouse spin_unlock_irqrestore(&card->param_queue_lock, flags); 44401e2ffacSDavid Woodhouse return found; 44501e2ffacSDavid Woodhouse } 44601e2ffacSDavid Woodhouse 4479c54004eSDavid Woodhouse static ssize_t console_show(struct device *dev, struct device_attribute *attr, 4489c54004eSDavid Woodhouse char *buf) 4499c54004eSDavid Woodhouse { 4509c54004eSDavid Woodhouse struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); 4519c54004eSDavid Woodhouse struct solos_card *card = atmdev->dev_data; 4529c54004eSDavid Woodhouse struct sk_buff *skb; 453f1ee89d5SJiri Slaby unsigned int len; 4549c54004eSDavid Woodhouse 4559c54004eSDavid Woodhouse spin_lock(&card->cli_queue_lock); 4569c54004eSDavid Woodhouse skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]); 4579c54004eSDavid Woodhouse spin_unlock(&card->cli_queue_lock); 4589c54004eSDavid Woodhouse if(skb == NULL) 4599c54004eSDavid Woodhouse return sprintf(buf, "No data.\n"); 4609c54004eSDavid Woodhouse 461f1ee89d5SJiri Slaby len = skb->len; 462f1ee89d5SJiri Slaby memcpy(buf, skb->data, len); 4639c54004eSDavid Woodhouse 4649c54004eSDavid Woodhouse kfree_skb(skb); 465f1ee89d5SJiri Slaby return len; 4669c54004eSDavid Woodhouse } 4679c54004eSDavid Woodhouse 4689c54004eSDavid Woodhouse static int send_command(struct solos_card *card, int dev, const char *buf, size_t size) 4699c54004eSDavid Woodhouse { 4709c54004eSDavid Woodhouse struct sk_buff *skb; 4719c54004eSDavid Woodhouse struct pkt_hdr *header; 4729c54004eSDavid Woodhouse 4739c54004eSDavid Woodhouse if (size > (BUF_SIZE - sizeof(*header))) { 4749c54004eSDavid Woodhouse dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); 4759c54004eSDavid Woodhouse return 0; 4769c54004eSDavid Woodhouse } 4779c54004eSDavid Woodhouse skb = alloc_skb(size + sizeof(*header), GFP_ATOMIC); 4789c54004eSDavid Woodhouse if (!skb) { 4799c54004eSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff in send_command()\n"); 4809c54004eSDavid Woodhouse return 0; 4819c54004eSDavid Woodhouse } 4829c54004eSDavid Woodhouse 4839c54004eSDavid Woodhouse header = (void *)skb_put(skb, sizeof(*header)); 4849c54004eSDavid Woodhouse 4859c54004eSDavid Woodhouse header->size = cpu_to_le16(size); 4869c54004eSDavid Woodhouse header->vpi = cpu_to_le16(0); 4879c54004eSDavid Woodhouse header->vci = cpu_to_le16(0); 4889c54004eSDavid Woodhouse header->type = cpu_to_le16(PKT_COMMAND); 4899c54004eSDavid Woodhouse 4909c54004eSDavid Woodhouse memcpy(skb_put(skb, size), buf, size); 4919c54004eSDavid Woodhouse 4929c54004eSDavid Woodhouse fpga_queue(card, dev, skb, NULL); 4939c54004eSDavid Woodhouse 4949c54004eSDavid Woodhouse return 0; 4959c54004eSDavid Woodhouse } 4969c54004eSDavid Woodhouse 4979c54004eSDavid Woodhouse static ssize_t console_store(struct device *dev, struct device_attribute *attr, 4989c54004eSDavid Woodhouse const char *buf, size_t count) 4999c54004eSDavid Woodhouse { 5009c54004eSDavid Woodhouse struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); 5019c54004eSDavid Woodhouse struct solos_card *card = atmdev->dev_data; 5029c54004eSDavid Woodhouse int err; 5039c54004eSDavid Woodhouse 5049c54004eSDavid Woodhouse err = send_command(card, SOLOS_CHAN(atmdev), buf, count); 5059c54004eSDavid Woodhouse 5069c54004eSDavid Woodhouse return err?:count; 5079c54004eSDavid Woodhouse } 5089c54004eSDavid Woodhouse 509f9baad02SNathan Williams struct geos_gpio_attr { 510f9baad02SNathan Williams struct device_attribute attr; 511f9baad02SNathan Williams int offset; 512f9baad02SNathan Williams }; 513f9baad02SNathan Williams 514f9baad02SNathan Williams #define SOLOS_GPIO_ATTR(_name, _mode, _show, _store, _offset) \ 515f9baad02SNathan Williams struct geos_gpio_attr gpio_attr_##_name = { \ 516f9baad02SNathan Williams .attr = __ATTR(_name, _mode, _show, _store), \ 517f9baad02SNathan Williams .offset = _offset } 518f9baad02SNathan Williams 519f9baad02SNathan Williams static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr, 520f9baad02SNathan Williams const char *buf, size_t count) 521f9baad02SNathan Williams { 522f9baad02SNathan Williams struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); 523f9baad02SNathan Williams struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); 524f9baad02SNathan Williams struct solos_card *card = pci_get_drvdata(pdev); 525f9baad02SNathan Williams uint32_t data32; 526f9baad02SNathan Williams 527f9baad02SNathan Williams if (count != 1 && (count != 2 || buf[1] != '\n')) 528f9baad02SNathan Williams return -EINVAL; 529f9baad02SNathan Williams 530f9baad02SNathan Williams spin_lock_irq(&card->param_queue_lock); 531f9baad02SNathan Williams data32 = ioread32(card->config_regs + GPIO_STATUS); 532f9baad02SNathan Williams if (buf[0] == '1') { 533f9baad02SNathan Williams data32 |= 1 << gattr->offset; 534f9baad02SNathan Williams iowrite32(data32, card->config_regs + GPIO_STATUS); 535f9baad02SNathan Williams } else if (buf[0] == '0') { 536f9baad02SNathan Williams data32 &= ~(1 << gattr->offset); 537f9baad02SNathan Williams iowrite32(data32, card->config_regs + GPIO_STATUS); 538f9baad02SNathan Williams } else { 539f9baad02SNathan Williams count = -EINVAL; 540f9baad02SNathan Williams } 54129042073SDan Carpenter spin_unlock_irq(&card->param_queue_lock); 542f9baad02SNathan Williams return count; 543f9baad02SNathan Williams } 544f9baad02SNathan Williams 545f9baad02SNathan Williams static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr, 546f9baad02SNathan Williams char *buf) 547f9baad02SNathan Williams { 548f9baad02SNathan Williams struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); 549f9baad02SNathan Williams struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); 550f9baad02SNathan Williams struct solos_card *card = pci_get_drvdata(pdev); 551f9baad02SNathan Williams uint32_t data32; 552f9baad02SNathan Williams 553f9baad02SNathan Williams data32 = ioread32(card->config_regs + GPIO_STATUS); 554f9baad02SNathan Williams data32 = (data32 >> gattr->offset) & 1; 555f9baad02SNathan Williams 556f9baad02SNathan Williams return sprintf(buf, "%d\n", data32); 557f9baad02SNathan Williams } 558f9baad02SNathan Williams 559f9baad02SNathan Williams static ssize_t hardware_show(struct device *dev, struct device_attribute *attr, 560f9baad02SNathan Williams char *buf) 561f9baad02SNathan Williams { 562f9baad02SNathan Williams struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); 563f9baad02SNathan Williams struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); 564f9baad02SNathan Williams struct solos_card *card = pci_get_drvdata(pdev); 565f9baad02SNathan Williams uint32_t data32; 566f9baad02SNathan Williams 567f9baad02SNathan Williams data32 = ioread32(card->config_regs + GPIO_STATUS); 568f9baad02SNathan Williams switch (gattr->offset) { 569f9baad02SNathan Williams case 0: 570f9baad02SNathan Williams /* HardwareVersion */ 571f9baad02SNathan Williams data32 = data32 & 0x1F; 572f9baad02SNathan Williams break; 573f9baad02SNathan Williams case 1: 574f9baad02SNathan Williams /* HardwareVariant */ 575f9baad02SNathan Williams data32 = (data32 >> 5) & 0x0F; 576f9baad02SNathan Williams break; 577f9baad02SNathan Williams } 578f9baad02SNathan Williams return sprintf(buf, "%d\n", data32); 579f9baad02SNathan Williams } 580f9baad02SNathan Williams 5819c54004eSDavid Woodhouse static DEVICE_ATTR(console, 0644, console_show, console_store); 5829c54004eSDavid Woodhouse 583d057f0a4SDavid Woodhouse 584d057f0a4SDavid Woodhouse #define SOLOS_ATTR_RO(x) static DEVICE_ATTR(x, 0444, solos_param_show, NULL); 585d057f0a4SDavid Woodhouse #define SOLOS_ATTR_RW(x) static DEVICE_ATTR(x, 0644, solos_param_show, solos_param_store); 586d057f0a4SDavid Woodhouse 587d057f0a4SDavid Woodhouse #include "solos-attrlist.c" 588d057f0a4SDavid Woodhouse 589f9baad02SNathan Williams static SOLOS_GPIO_ATTR(GPIO1, 0644, geos_gpio_show, geos_gpio_store, 9); 590f9baad02SNathan Williams static SOLOS_GPIO_ATTR(GPIO2, 0644, geos_gpio_show, geos_gpio_store, 10); 591f9baad02SNathan Williams static SOLOS_GPIO_ATTR(GPIO3, 0644, geos_gpio_show, geos_gpio_store, 11); 592f9baad02SNathan Williams static SOLOS_GPIO_ATTR(GPIO4, 0644, geos_gpio_show, geos_gpio_store, 12); 593f9baad02SNathan Williams static SOLOS_GPIO_ATTR(GPIO5, 0644, geos_gpio_show, geos_gpio_store, 13); 594f9baad02SNathan Williams static SOLOS_GPIO_ATTR(PushButton, 0444, geos_gpio_show, NULL, 14); 595f9baad02SNathan Williams static SOLOS_GPIO_ATTR(HardwareVersion, 0444, hardware_show, NULL, 0); 596f9baad02SNathan Williams static SOLOS_GPIO_ATTR(HardwareVariant, 0444, hardware_show, NULL, 1); 597d057f0a4SDavid Woodhouse #undef SOLOS_ATTR_RO 598d057f0a4SDavid Woodhouse #undef SOLOS_ATTR_RW 599d057f0a4SDavid Woodhouse 600d057f0a4SDavid Woodhouse #define SOLOS_ATTR_RO(x) &dev_attr_##x.attr, 601d057f0a4SDavid Woodhouse #define SOLOS_ATTR_RW(x) &dev_attr_##x.attr, 602d057f0a4SDavid Woodhouse 603d057f0a4SDavid Woodhouse static struct attribute *solos_attrs[] = { 604d057f0a4SDavid Woodhouse #include "solos-attrlist.c" 605d057f0a4SDavid Woodhouse NULL 606d057f0a4SDavid Woodhouse }; 607d057f0a4SDavid Woodhouse 608d057f0a4SDavid Woodhouse static struct attribute_group solos_attr_group = { 609d057f0a4SDavid Woodhouse .attrs = solos_attrs, 610d057f0a4SDavid Woodhouse .name = "parameters", 611d057f0a4SDavid Woodhouse }; 6129c54004eSDavid Woodhouse 613f9baad02SNathan Williams static struct attribute *gpio_attrs[] = { 614f9baad02SNathan Williams &gpio_attr_GPIO1.attr.attr, 615f9baad02SNathan Williams &gpio_attr_GPIO2.attr.attr, 616f9baad02SNathan Williams &gpio_attr_GPIO3.attr.attr, 617f9baad02SNathan Williams &gpio_attr_GPIO4.attr.attr, 618f9baad02SNathan Williams &gpio_attr_GPIO5.attr.attr, 619f9baad02SNathan Williams &gpio_attr_PushButton.attr.attr, 620f9baad02SNathan Williams &gpio_attr_HardwareVersion.attr.attr, 621f9baad02SNathan Williams &gpio_attr_HardwareVariant.attr.attr, 622f9baad02SNathan Williams NULL 623f9baad02SNathan Williams }; 624f9baad02SNathan Williams 625f9baad02SNathan Williams static struct attribute_group gpio_attr_group = { 626f9baad02SNathan Williams .attrs = gpio_attrs, 627f9baad02SNathan Williams .name = "gpio", 628f9baad02SNathan Williams }; 629f9baad02SNathan Williams 630fa755b9fSDavid Woodhouse static int flash_upgrade(struct solos_card *card, int chip) 631fa755b9fSDavid Woodhouse { 632fa755b9fSDavid Woodhouse const struct firmware *fw; 633fa755b9fSDavid Woodhouse const char *fw_name; 6347c4015bdSSimon Farnsworth int blocksize = 0; 6357c4015bdSSimon Farnsworth int numblocks = 0; 636fa755b9fSDavid Woodhouse int offset; 637fa755b9fSDavid Woodhouse 6387adcdb4cSAndrew Morton switch (chip) { 6397adcdb4cSAndrew Morton case 0: 640fa755b9fSDavid Woodhouse fw_name = "solos-FPGA.bin"; 64113af8164SNathan Williams if (card->atmel_flash) 64213af8164SNathan Williams blocksize = ATMEL_FPGA_BLOCK; 64313af8164SNathan Williams else 64413af8164SNathan Williams blocksize = SPI_FLASH_BLOCK; 6457adcdb4cSAndrew Morton break; 6467adcdb4cSAndrew Morton case 1: 647fa755b9fSDavid Woodhouse fw_name = "solos-Firmware.bin"; 64813af8164SNathan Williams if (card->atmel_flash) 64913af8164SNathan Williams blocksize = ATMEL_SOLOS_BLOCK; 65013af8164SNathan Williams else 65113af8164SNathan Williams blocksize = SPI_FLASH_BLOCK; 6527adcdb4cSAndrew Morton break; 6537adcdb4cSAndrew Morton case 2: 6544dbedf43SNathan Williams if (card->fpga_version > LEGACY_BUFFERS){ 6554dbedf43SNathan Williams fw_name = "solos-db-FPGA.bin"; 65613af8164SNathan Williams if (card->atmel_flash) 65713af8164SNathan Williams blocksize = ATMEL_FPGA_BLOCK; 65813af8164SNathan Williams else 65913af8164SNathan Williams blocksize = SPI_FLASH_BLOCK; 6604dbedf43SNathan Williams } else { 6617adcdb4cSAndrew Morton dev_info(&card->dev->dev, "FPGA version doesn't support" 6627adcdb4cSAndrew Morton " daughter board upgrades\n"); 6634dbedf43SNathan Williams return -EPERM; 6644dbedf43SNathan Williams } 6657adcdb4cSAndrew Morton break; 6667adcdb4cSAndrew Morton case 3: 6674dbedf43SNathan Williams if (card->fpga_version > LEGACY_BUFFERS){ 6684dbedf43SNathan Williams fw_name = "solos-Firmware.bin"; 66913af8164SNathan Williams if (card->atmel_flash) 67013af8164SNathan Williams blocksize = ATMEL_SOLOS_BLOCK; 67113af8164SNathan Williams else 67213af8164SNathan Williams blocksize = SPI_FLASH_BLOCK; 6734dbedf43SNathan Williams } else { 6747adcdb4cSAndrew Morton dev_info(&card->dev->dev, "FPGA version doesn't support" 6757adcdb4cSAndrew Morton " daughter board upgrades\n"); 6764dbedf43SNathan Williams return -EPERM; 6774dbedf43SNathan Williams } 6787adcdb4cSAndrew Morton break; 6797adcdb4cSAndrew Morton default: 6807adcdb4cSAndrew Morton return -ENODEV; 6814dbedf43SNathan Williams } 6824dbedf43SNathan Williams 683fa755b9fSDavid Woodhouse if (request_firmware(&fw, fw_name, &card->dev->dev)) 684fa755b9fSDavid Woodhouse return -ENOENT; 685fa755b9fSDavid Woodhouse 686fa755b9fSDavid Woodhouse dev_info(&card->dev->dev, "Flash upgrade starting\n"); 687fa755b9fSDavid Woodhouse 68813af8164SNathan Williams /* New FPGAs require driver version before permitting flash upgrades */ 68913af8164SNathan Williams iowrite32(DRIVER_VERSION, card->config_regs + DRIVER_VER); 69013af8164SNathan Williams 691fa755b9fSDavid Woodhouse numblocks = fw->size / blocksize; 692fa755b9fSDavid Woodhouse dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size); 693fa755b9fSDavid Woodhouse dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks); 6947c4015bdSSimon Farnsworth 6957c4015bdSSimon Farnsworth dev_info(&card->dev->dev, "Changing FPGA to Update mode\n"); 6967c4015bdSSimon Farnsworth iowrite32(1, card->config_regs + FPGA_MODE); 69706091ed6SDavid S. Miller (void) ioread32(card->config_regs + FPGA_MODE); 6987c4015bdSSimon Farnsworth 699fa755b9fSDavid Woodhouse /* Set mode to Chip Erase */ 7004dbedf43SNathan Williams if(chip == 0 || chip == 2) 7014dbedf43SNathan Williams dev_info(&card->dev->dev, "Set FPGA Flash mode to FPGA Chip Erase\n"); 7024dbedf43SNathan Williams if(chip == 1 || chip == 3) 7034dbedf43SNathan Williams dev_info(&card->dev->dev, "Set FPGA Flash mode to Solos Chip Erase\n"); 704fa755b9fSDavid Woodhouse iowrite32((chip * 2), card->config_regs + FLASH_MODE); 705fa755b9fSDavid Woodhouse 706fa755b9fSDavid Woodhouse 707fa755b9fSDavid Woodhouse iowrite32(1, card->config_regs + WRITE_FLASH); 708fa755b9fSDavid Woodhouse wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY)); 709fa755b9fSDavid Woodhouse 710fa755b9fSDavid Woodhouse for (offset = 0; offset < fw->size; offset += blocksize) { 7117c4015bdSSimon Farnsworth int i; 7127c4015bdSSimon Farnsworth 7137c4015bdSSimon Farnsworth /* Clear write flag */ 7147c4015bdSSimon Farnsworth iowrite32(0, card->config_regs + WRITE_FLASH); 715fa755b9fSDavid Woodhouse 7167c4015bdSSimon Farnsworth /* Set mode to Block Write */ 7177c4015bdSSimon Farnsworth /* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */ 718fa755b9fSDavid Woodhouse iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE); 7197c4015bdSSimon Farnsworth 72013af8164SNathan Williams /* Copy block to buffer, swapping each 16 bits for Atmel flash */ 721fa755b9fSDavid Woodhouse for(i = 0; i < blocksize; i += 4) { 72213af8164SNathan Williams uint32_t word; 72313af8164SNathan Williams if (card->atmel_flash) 72413af8164SNathan Williams word = swahb32p((uint32_t *)(fw->data + offset + i)); 72513af8164SNathan Williams else 72613af8164SNathan Williams word = *(uint32_t *)(fw->data + offset + i); 7274dbedf43SNathan Williams if(card->fpga_version > LEGACY_BUFFERS) 7284dbedf43SNathan Williams iowrite32(word, FLASH_BUF + i); 7294dbedf43SNathan Williams else 730fa755b9fSDavid Woodhouse iowrite32(word, RX_BUF(card, 3) + i); 731fa755b9fSDavid Woodhouse } 732fa755b9fSDavid Woodhouse 733fa755b9fSDavid Woodhouse /* Specify block number and then trigger flash write */ 734fa755b9fSDavid Woodhouse iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK); 735fa755b9fSDavid Woodhouse iowrite32(1, card->config_regs + WRITE_FLASH); 736fa755b9fSDavid Woodhouse wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY)); 737fa755b9fSDavid Woodhouse } 738fa755b9fSDavid Woodhouse 739fa755b9fSDavid Woodhouse release_firmware(fw); 7407c4015bdSSimon Farnsworth iowrite32(0, card->config_regs + WRITE_FLASH); 7417c4015bdSSimon Farnsworth iowrite32(0, card->config_regs + FPGA_MODE); 7427c4015bdSSimon Farnsworth iowrite32(0, card->config_regs + FLASH_MODE); 7437c4015bdSSimon Farnsworth dev_info(&card->dev->dev, "Returning FPGA to Data mode\n"); 744fa755b9fSDavid Woodhouse return 0; 7457c4015bdSSimon Farnsworth } 7467c4015bdSSimon Farnsworth 7479c54004eSDavid Woodhouse static irqreturn_t solos_irq(int irq, void *dev_id) 7489c54004eSDavid Woodhouse { 7499c54004eSDavid Woodhouse struct solos_card *card = dev_id; 7509c54004eSDavid Woodhouse int handled = 1; 7519c54004eSDavid Woodhouse 7529c54004eSDavid Woodhouse iowrite32(0, card->config_regs + IRQ_CLEAR); 7539c54004eSDavid Woodhouse 75435c2221bSDavid Woodhouse /* If we're up and running, just kick the tasklet to process TX/RX */ 755fa755b9fSDavid Woodhouse if (card->atmdev[0]) 7569c54004eSDavid Woodhouse tasklet_schedule(&card->tlet); 757fa755b9fSDavid Woodhouse else 758fa755b9fSDavid Woodhouse wake_up(&card->fw_wq); 7599c54004eSDavid Woodhouse 7609c54004eSDavid Woodhouse return IRQ_RETVAL(handled); 7619c54004eSDavid Woodhouse } 7629c54004eSDavid Woodhouse 7635f4d4e3fSDaeseok Youn static void solos_bh(unsigned long card_arg) 7649c54004eSDavid Woodhouse { 7659c54004eSDavid Woodhouse struct solos_card *card = (void *)card_arg; 7669c54004eSDavid Woodhouse uint32_t card_flags; 7679c54004eSDavid Woodhouse uint32_t rx_done = 0; 76835c2221bSDavid Woodhouse int port; 7699c54004eSDavid Woodhouse 77035c2221bSDavid Woodhouse /* 77135c2221bSDavid Woodhouse * Since fpga_tx() is going to need to read the flags under its lock, 77235c2221bSDavid Woodhouse * it can return them to us so that we don't have to hit PCI MMIO 77335c2221bSDavid Woodhouse * again for the same information 77435c2221bSDavid Woodhouse */ 77535c2221bSDavid Woodhouse card_flags = fpga_tx(card); 7769c54004eSDavid Woodhouse 7779c54004eSDavid Woodhouse for (port = 0; port < card->nr_ports; port++) { 7789c54004eSDavid Woodhouse if (card_flags & (0x10 << port)) { 77990937231SDavid Woodhouse struct pkt_hdr _hdr, *header; 7809c54004eSDavid Woodhouse struct sk_buff *skb; 7819c54004eSDavid Woodhouse struct atm_vcc *vcc; 7829c54004eSDavid Woodhouse int size; 7839c54004eSDavid Woodhouse 78490937231SDavid Woodhouse if (card->using_dma) { 78590937231SDavid Woodhouse skb = card->rx_skb[port]; 786eaf83e39SDavid Woodhouse card->rx_skb[port] = NULL; 78790937231SDavid Woodhouse 788eaf83e39SDavid Woodhouse pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, 789eaf83e39SDavid Woodhouse RX_DMA_SIZE, PCI_DMA_FROMDEVICE); 790eaf83e39SDavid Woodhouse 79190937231SDavid Woodhouse header = (void *)skb->data; 79290937231SDavid Woodhouse size = le16_to_cpu(header->size); 79390937231SDavid Woodhouse skb_put(skb, size + sizeof(*header)); 79490937231SDavid Woodhouse skb_pull(skb, sizeof(*header)); 79590937231SDavid Woodhouse } else { 79690937231SDavid Woodhouse header = &_hdr; 79790937231SDavid Woodhouse 7989c54004eSDavid Woodhouse rx_done |= 0x10 << port; 7999c54004eSDavid Woodhouse 80090937231SDavid Woodhouse memcpy_fromio(header, RX_BUF(card, port), sizeof(*header)); 8019c54004eSDavid Woodhouse 80290937231SDavid Woodhouse size = le16_to_cpu(header->size); 80378f857f2SNathan Williams if (size > (card->buffer_size - sizeof(*header))){ 80478f857f2SNathan Williams dev_warn(&card->dev->dev, "Invalid buffer size\n"); 80578f857f2SNathan Williams continue; 80678f857f2SNathan Williams } 8079c54004eSDavid Woodhouse 80887ebb186SDavid Woodhouse skb = alloc_skb(size + 1, GFP_ATOMIC); 8099c54004eSDavid Woodhouse if (!skb) { 8109c54004eSDavid Woodhouse if (net_ratelimit()) 8119c54004eSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); 8129c54004eSDavid Woodhouse continue; 8139c54004eSDavid Woodhouse } 8149c54004eSDavid Woodhouse 8159c54004eSDavid Woodhouse memcpy_fromio(skb_put(skb, size), 81690937231SDavid Woodhouse RX_BUF(card, port) + sizeof(*header), 8179c54004eSDavid Woodhouse size); 81890937231SDavid Woodhouse } 8199c54004eSDavid Woodhouse if (atmdebug) { 82018b429e7SPhilip A. Prindeville dev_info(&card->dev->dev, "Received: port %d\n", port); 8219c54004eSDavid Woodhouse dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", 82290937231SDavid Woodhouse size, le16_to_cpu(header->vpi), 82390937231SDavid Woodhouse le16_to_cpu(header->vci)); 8249c54004eSDavid Woodhouse print_buffer(skb); 8259c54004eSDavid Woodhouse } 8269c54004eSDavid Woodhouse 82790937231SDavid Woodhouse switch (le16_to_cpu(header->type)) { 8289c54004eSDavid Woodhouse case PKT_DATA: 82990937231SDavid Woodhouse vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi), 83090937231SDavid Woodhouse le16_to_cpu(header->vci)); 8319c54004eSDavid Woodhouse if (!vcc) { 8329c54004eSDavid Woodhouse if (net_ratelimit()) 8331e19e658SPhilip A. Prindeville dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", 8341e19e658SPhilip A. Prindeville le16_to_cpu(header->vpi), le16_to_cpu(header->vci), 8359c54004eSDavid Woodhouse port); 836007ef52bSNathan Williams dev_kfree_skb_any(skb); 837007ef52bSNathan Williams break; 8389c54004eSDavid Woodhouse } 8399c54004eSDavid Woodhouse atm_charge(vcc, skb->truesize); 8409c54004eSDavid Woodhouse vcc->push(vcc, skb); 8419c54004eSDavid Woodhouse atomic_inc(&vcc->stats->rx); 8429c54004eSDavid Woodhouse break; 8439c54004eSDavid Woodhouse 84487ebb186SDavid Woodhouse case PKT_STATUS: 84595852f48SDavid Woodhouse if (process_status(card, port, skb) && 84695852f48SDavid Woodhouse net_ratelimit()) { 84795852f48SDavid Woodhouse dev_warn(&card->dev->dev, "Bad status packet of %d bytes on port %d:\n", skb->len, port); 84895852f48SDavid Woodhouse print_buffer(skb); 84995852f48SDavid Woodhouse } 850eaf83e39SDavid Woodhouse dev_kfree_skb_any(skb); 85187ebb186SDavid Woodhouse break; 85287ebb186SDavid Woodhouse 8539c54004eSDavid Woodhouse case PKT_COMMAND: 8549c54004eSDavid Woodhouse default: /* FIXME: Not really, surely? */ 85501e2ffacSDavid Woodhouse if (process_command(card, port, skb)) 85601e2ffacSDavid Woodhouse break; 8579c54004eSDavid Woodhouse spin_lock(&card->cli_queue_lock); 8589c54004eSDavid Woodhouse if (skb_queue_len(&card->cli_queue[port]) > 10) { 8599c54004eSDavid Woodhouse if (net_ratelimit()) 8609c54004eSDavid Woodhouse dev_warn(&card->dev->dev, "Dropping console response on port %d\n", 8619c54004eSDavid Woodhouse port); 862eaf83e39SDavid Woodhouse dev_kfree_skb_any(skb); 8639c54004eSDavid Woodhouse } else 8649c54004eSDavid Woodhouse skb_queue_tail(&card->cli_queue[port], skb); 8659c54004eSDavid Woodhouse spin_unlock(&card->cli_queue_lock); 8669c54004eSDavid Woodhouse break; 8679c54004eSDavid Woodhouse } 8689c54004eSDavid Woodhouse } 869eaf83e39SDavid Woodhouse /* Allocate RX skbs for any ports which need them */ 870eaf83e39SDavid Woodhouse if (card->using_dma && card->atmdev[port] && 871eaf83e39SDavid Woodhouse !card->rx_skb[port]) { 872eaf83e39SDavid Woodhouse struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC); 873eaf83e39SDavid Woodhouse if (skb) { 874eaf83e39SDavid Woodhouse SKB_CB(skb)->dma_addr = 875eaf83e39SDavid Woodhouse pci_map_single(card->dev, skb->data, 876eaf83e39SDavid Woodhouse RX_DMA_SIZE, PCI_DMA_FROMDEVICE); 877eaf83e39SDavid Woodhouse iowrite32(SKB_CB(skb)->dma_addr, 878eaf83e39SDavid Woodhouse card->config_regs + RX_DMA_ADDR(port)); 879eaf83e39SDavid Woodhouse card->rx_skb[port] = skb; 880eaf83e39SDavid Woodhouse } else { 881eaf83e39SDavid Woodhouse if (net_ratelimit()) 882eaf83e39SDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate RX skb"); 883eaf83e39SDavid Woodhouse 884eaf83e39SDavid Woodhouse /* We'll have to try again later */ 885eaf83e39SDavid Woodhouse tasklet_schedule(&card->tlet); 886eaf83e39SDavid Woodhouse } 887eaf83e39SDavid Woodhouse } 8889c54004eSDavid Woodhouse } 8899c54004eSDavid Woodhouse if (rx_done) 8909c54004eSDavid Woodhouse iowrite32(rx_done, card->config_regs + FLAGS_ADDR); 8919c54004eSDavid Woodhouse 8929c54004eSDavid Woodhouse return; 8939c54004eSDavid Woodhouse } 8949c54004eSDavid Woodhouse 8959c54004eSDavid Woodhouse static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) 8969c54004eSDavid Woodhouse { 8979c54004eSDavid Woodhouse struct hlist_head *head; 8989c54004eSDavid Woodhouse struct atm_vcc *vcc = NULL; 8999c54004eSDavid Woodhouse struct sock *s; 9009c54004eSDavid Woodhouse 9019c54004eSDavid Woodhouse read_lock(&vcc_sklist_lock); 9029c54004eSDavid Woodhouse head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; 903b67bfe0dSSasha Levin sk_for_each(s, head) { 9049c54004eSDavid Woodhouse vcc = atm_sk(s); 9059c54004eSDavid Woodhouse if (vcc->dev == dev && vcc->vci == vci && 9061f6ea6e5SDavid Woodhouse vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE && 9071f6ea6e5SDavid Woodhouse test_bit(ATM_VF_READY, &vcc->flags)) 9089c54004eSDavid Woodhouse goto out; 9099c54004eSDavid Woodhouse } 9109c54004eSDavid Woodhouse vcc = NULL; 9119c54004eSDavid Woodhouse out: 9129c54004eSDavid Woodhouse read_unlock(&vcc_sklist_lock); 9139c54004eSDavid Woodhouse return vcc; 9149c54004eSDavid Woodhouse } 9159c54004eSDavid Woodhouse 9169c54004eSDavid Woodhouse static int popen(struct atm_vcc *vcc) 9179c54004eSDavid Woodhouse { 9189c54004eSDavid Woodhouse struct solos_card *card = vcc->dev->dev_data; 9199c54004eSDavid Woodhouse struct sk_buff *skb; 9209c54004eSDavid Woodhouse struct pkt_hdr *header; 9219c54004eSDavid Woodhouse 922b28a4b9aSDavid Woodhouse if (vcc->qos.aal != ATM_AAL5) { 923b28a4b9aSDavid Woodhouse dev_warn(&card->dev->dev, "Unsupported ATM type %d\n", 924b28a4b9aSDavid Woodhouse vcc->qos.aal); 925b28a4b9aSDavid Woodhouse return -EINVAL; 926b28a4b9aSDavid Woodhouse } 927b28a4b9aSDavid Woodhouse 928a1db5c5bSDavid Woodhouse skb = alloc_skb(sizeof(*header), GFP_KERNEL); 929da1ab3e2SJesper Juhl if (!skb) { 930da1ab3e2SJesper Juhl if (net_ratelimit()) 9319c54004eSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); 9329c54004eSDavid Woodhouse return -ENOMEM; 9339c54004eSDavid Woodhouse } 9349c54004eSDavid Woodhouse header = (void *)skb_put(skb, sizeof(*header)); 9359c54004eSDavid Woodhouse 936b76811afSDavid Woodhouse header->size = cpu_to_le16(0); 9379c54004eSDavid Woodhouse header->vpi = cpu_to_le16(vcc->vpi); 9389c54004eSDavid Woodhouse header->vci = cpu_to_le16(vcc->vci); 9399c54004eSDavid Woodhouse header->type = cpu_to_le16(PKT_POPEN); 9409c54004eSDavid Woodhouse 9419c54004eSDavid Woodhouse fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); 9429c54004eSDavid Woodhouse 943bdc54625SDavid Woodhouse set_bit(ATM_VF_ADDR, &vcc->flags); 9449c54004eSDavid Woodhouse set_bit(ATM_VF_READY, &vcc->flags); 9459c54004eSDavid Woodhouse 9469c54004eSDavid Woodhouse return 0; 9479c54004eSDavid Woodhouse } 9489c54004eSDavid Woodhouse 9499c54004eSDavid Woodhouse static void pclose(struct atm_vcc *vcc) 9509c54004eSDavid Woodhouse { 9519c54004eSDavid Woodhouse struct solos_card *card = vcc->dev->dev_data; 9527ad3eadeSDavid Woodhouse unsigned char port = SOLOS_CHAN(vcc->dev); 953213e85d3SDavid Woodhouse struct sk_buff *skb, *tmpskb; 9549c54004eSDavid Woodhouse struct pkt_hdr *header; 9559c54004eSDavid Woodhouse 956213e85d3SDavid Woodhouse /* Remove any yet-to-be-transmitted packets from the pending queue */ 957213e85d3SDavid Woodhouse spin_lock(&card->tx_queue_lock); 958213e85d3SDavid Woodhouse skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { 959213e85d3SDavid Woodhouse if (SKB_CB(skb)->vcc == vcc) { 960213e85d3SDavid Woodhouse skb_unlink(skb, &card->tx_queue[port]); 961213e85d3SDavid Woodhouse solos_pop(vcc, skb); 962213e85d3SDavid Woodhouse } 963213e85d3SDavid Woodhouse } 964213e85d3SDavid Woodhouse spin_unlock(&card->tx_queue_lock); 965213e85d3SDavid Woodhouse 966a1db5c5bSDavid Woodhouse skb = alloc_skb(sizeof(*header), GFP_KERNEL); 9679c54004eSDavid Woodhouse if (!skb) { 9689c54004eSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); 9699c54004eSDavid Woodhouse return; 9709c54004eSDavid Woodhouse } 9719c54004eSDavid Woodhouse header = (void *)skb_put(skb, sizeof(*header)); 9729c54004eSDavid Woodhouse 973b76811afSDavid Woodhouse header->size = cpu_to_le16(0); 9749c54004eSDavid Woodhouse header->vpi = cpu_to_le16(vcc->vpi); 9759c54004eSDavid Woodhouse header->vci = cpu_to_le16(vcc->vci); 9769c54004eSDavid Woodhouse header->type = cpu_to_le16(PKT_PCLOSE); 9779c54004eSDavid Woodhouse 9787ad3eadeSDavid Woodhouse skb_get(skb); 9797ad3eadeSDavid Woodhouse fpga_queue(card, port, skb, NULL); 9809c54004eSDavid Woodhouse 9817ad3eadeSDavid Woodhouse if (!wait_event_timeout(card->param_wq, !skb_shared(skb), 5 * HZ)) 9827ad3eadeSDavid Woodhouse dev_warn(&card->dev->dev, 9837ad3eadeSDavid Woodhouse "Timeout waiting for VCC close on port %d\n", port); 9847ad3eadeSDavid Woodhouse 9857ad3eadeSDavid Woodhouse dev_kfree_skb(skb); 9867ad3eadeSDavid Woodhouse 9871f6ea6e5SDavid Woodhouse /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the 9881f6ea6e5SDavid Woodhouse tasklet has finished processing any incoming packets (and, more to 9891f6ea6e5SDavid Woodhouse the point, using the vcc pointer). */ 9901f6ea6e5SDavid Woodhouse tasklet_unlock_wait(&card->tlet); 991213e85d3SDavid Woodhouse 992213e85d3SDavid Woodhouse clear_bit(ATM_VF_ADDR, &vcc->flags); 993213e85d3SDavid Woodhouse 9949c54004eSDavid Woodhouse return; 9959c54004eSDavid Woodhouse } 9969c54004eSDavid Woodhouse 9979c54004eSDavid Woodhouse static int print_buffer(struct sk_buff *buf) 9989c54004eSDavid Woodhouse { 9999c54004eSDavid Woodhouse int len,i; 10009c54004eSDavid Woodhouse char msg[500]; 10019c54004eSDavid Woodhouse char item[10]; 10029c54004eSDavid Woodhouse 10039c54004eSDavid Woodhouse len = buf->len; 10049c54004eSDavid Woodhouse for (i = 0; i < len; i++){ 10059c54004eSDavid Woodhouse if(i % 8 == 0) 10069c54004eSDavid Woodhouse sprintf(msg, "%02X: ", i); 10079c54004eSDavid Woodhouse 10089c54004eSDavid Woodhouse sprintf(item,"%02X ",*(buf->data + i)); 10099c54004eSDavid Woodhouse strcat(msg, item); 10109c54004eSDavid Woodhouse if(i % 8 == 7) { 10119c54004eSDavid Woodhouse sprintf(item, "\n"); 10129c54004eSDavid Woodhouse strcat(msg, item); 10139c54004eSDavid Woodhouse printk(KERN_DEBUG "%s", msg); 10149c54004eSDavid Woodhouse } 10159c54004eSDavid Woodhouse } 10169c54004eSDavid Woodhouse if (i % 8 != 0) { 10179c54004eSDavid Woodhouse sprintf(item, "\n"); 10189c54004eSDavid Woodhouse strcat(msg, item); 10199c54004eSDavid Woodhouse printk(KERN_DEBUG "%s", msg); 10209c54004eSDavid Woodhouse } 10219c54004eSDavid Woodhouse printk(KERN_DEBUG "\n"); 10229c54004eSDavid Woodhouse 10239c54004eSDavid Woodhouse return 0; 10249c54004eSDavid Woodhouse } 10259c54004eSDavid Woodhouse 10269c54004eSDavid Woodhouse static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, 10279c54004eSDavid Woodhouse struct atm_vcc *vcc) 10289c54004eSDavid Woodhouse { 10299c54004eSDavid Woodhouse int old_len; 1030f69e4170SDavid Woodhouse unsigned long flags; 10319c54004eSDavid Woodhouse 103290937231SDavid Woodhouse SKB_CB(skb)->vcc = vcc; 10339c54004eSDavid Woodhouse 1034f69e4170SDavid Woodhouse spin_lock_irqsave(&card->tx_queue_lock, flags); 10359c54004eSDavid Woodhouse old_len = skb_queue_len(&card->tx_queue[port]); 10369c54004eSDavid Woodhouse skb_queue_tail(&card->tx_queue[port], skb); 103735c2221bSDavid Woodhouse if (!old_len) 1038f69e4170SDavid Woodhouse card->tx_mask |= (1 << port); 1039f69e4170SDavid Woodhouse spin_unlock_irqrestore(&card->tx_queue_lock, flags); 10409c54004eSDavid Woodhouse 1041f69e4170SDavid Woodhouse /* Theoretically we could just schedule the tasklet here, but 1042f69e4170SDavid Woodhouse that introduces latency we don't want -- it's noticeable */ 10439c54004eSDavid Woodhouse if (!old_len) 10449c54004eSDavid Woodhouse fpga_tx(card); 10459c54004eSDavid Woodhouse } 10469c54004eSDavid Woodhouse 104735c2221bSDavid Woodhouse static uint32_t fpga_tx(struct solos_card *card) 10489c54004eSDavid Woodhouse { 104935c2221bSDavid Woodhouse uint32_t tx_pending, card_flags; 10509c54004eSDavid Woodhouse uint32_t tx_started = 0; 10519c54004eSDavid Woodhouse struct sk_buff *skb; 10529c54004eSDavid Woodhouse struct atm_vcc *vcc; 10539c54004eSDavid Woodhouse unsigned char port; 10549c54004eSDavid Woodhouse unsigned long flags; 10559c54004eSDavid Woodhouse 10569c54004eSDavid Woodhouse spin_lock_irqsave(&card->tx_lock, flags); 10579c54004eSDavid Woodhouse 105835c2221bSDavid Woodhouse card_flags = ioread32(card->config_regs + FLAGS_ADDR); 105935c2221bSDavid Woodhouse /* 106035c2221bSDavid Woodhouse * The queue lock is required for _writing_ to tx_mask, but we're 106135c2221bSDavid Woodhouse * OK to read it here without locking. The only potential update 106235c2221bSDavid Woodhouse * that we could race with is in fpga_queue() where it sets a bit 106335c2221bSDavid Woodhouse * for a new port... but it's going to call this function again if 106435c2221bSDavid Woodhouse * it's doing that, anyway. 106535c2221bSDavid Woodhouse */ 106635c2221bSDavid Woodhouse tx_pending = card->tx_mask & ~card_flags; 10679c54004eSDavid Woodhouse 106835c2221bSDavid Woodhouse for (port = 0; tx_pending; tx_pending >>= 1, port++) { 106935c2221bSDavid Woodhouse if (tx_pending & 1) { 1070eaf83e39SDavid Woodhouse struct sk_buff *oldskb = card->tx_skb[port]; 1071cae49edeSDavid Woodhouse if (oldskb) { 1072eaf83e39SDavid Woodhouse pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, 1073eaf83e39SDavid Woodhouse oldskb->len, PCI_DMA_TODEVICE); 1074cae49edeSDavid Woodhouse card->tx_skb[port] = NULL; 1075cae49edeSDavid Woodhouse } 10769c54004eSDavid Woodhouse spin_lock(&card->tx_queue_lock); 10779c54004eSDavid Woodhouse skb = skb_dequeue(&card->tx_queue[port]); 1078f69e4170SDavid Woodhouse if (!skb) 1079f69e4170SDavid Woodhouse card->tx_mask &= ~(1 << port); 10809c54004eSDavid Woodhouse spin_unlock(&card->tx_queue_lock); 10819c54004eSDavid Woodhouse 1082eaf83e39SDavid Woodhouse if (skb && !card->using_dma) { 1083eaf83e39SDavid Woodhouse memcpy_toio(TX_BUF(card, port), skb->data, skb->len); 1084bdc54625SDavid Woodhouse tx_started |= 1 << port; 1085eaf83e39SDavid Woodhouse oldskb = skb; /* We're done with this skb already */ 1086eaf83e39SDavid Woodhouse } else if (skb && card->using_dma) { 1087152a2a8bSDavid Woodhouse unsigned char *data = skb->data; 1088152a2a8bSDavid Woodhouse if ((unsigned long)data & card->dma_alignment) { 1089152a2a8bSDavid Woodhouse data = card->dma_bounce + (BUF_SIZE * port); 1090152a2a8bSDavid Woodhouse memcpy(data, skb->data, skb->len); 1091152a2a8bSDavid Woodhouse } 1092152a2a8bSDavid Woodhouse SKB_CB(skb)->dma_addr = pci_map_single(card->dev, data, 1093eaf83e39SDavid Woodhouse skb->len, PCI_DMA_TODEVICE); 1094b4bd8ad9SDavid Woodhouse card->tx_skb[port] = skb; 1095eaf83e39SDavid Woodhouse iowrite32(SKB_CB(skb)->dma_addr, 1096eaf83e39SDavid Woodhouse card->config_regs + TX_DMA_ADDR(port)); 1097eaf83e39SDavid Woodhouse } 1098eaf83e39SDavid Woodhouse 1099eaf83e39SDavid Woodhouse if (!oldskb) 11009c54004eSDavid Woodhouse continue; 11019c54004eSDavid Woodhouse 1102eaf83e39SDavid Woodhouse /* Clean up and free oldskb now it's gone */ 11039c54004eSDavid Woodhouse if (atmdebug) { 110418b429e7SPhilip A. Prindeville struct pkt_hdr *header = (void *)oldskb->data; 110518b429e7SPhilip A. Prindeville int size = le16_to_cpu(header->size); 110618b429e7SPhilip A. Prindeville 110718b429e7SPhilip A. Prindeville skb_pull(oldskb, sizeof(*header)); 11089c54004eSDavid Woodhouse dev_info(&card->dev->dev, "Transmitted: port %d\n", 11099c54004eSDavid Woodhouse port); 111018b429e7SPhilip A. Prindeville dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", 111118b429e7SPhilip A. Prindeville size, le16_to_cpu(header->vpi), 111218b429e7SPhilip A. Prindeville le16_to_cpu(header->vci)); 1113eaf83e39SDavid Woodhouse print_buffer(oldskb); 11149c54004eSDavid Woodhouse } 11159c54004eSDavid Woodhouse 111690937231SDavid Woodhouse vcc = SKB_CB(oldskb)->vcc; 11179c54004eSDavid Woodhouse 11189c54004eSDavid Woodhouse if (vcc) { 11199c54004eSDavid Woodhouse atomic_inc(&vcc->stats->tx); 112090937231SDavid Woodhouse solos_pop(vcc, oldskb); 11217ad3eadeSDavid Woodhouse } else { 112290937231SDavid Woodhouse dev_kfree_skb_irq(oldskb); 11237ad3eadeSDavid Woodhouse wake_up(&card->param_wq); 11247ad3eadeSDavid Woodhouse } 11259c54004eSDavid Woodhouse } 11269c54004eSDavid Woodhouse } 1127bdc54625SDavid Woodhouse /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ 11289c54004eSDavid Woodhouse if (tx_started) 11299c54004eSDavid Woodhouse iowrite32(tx_started, card->config_regs + FLAGS_ADDR); 11309c54004eSDavid Woodhouse 11319c54004eSDavid Woodhouse spin_unlock_irqrestore(&card->tx_lock, flags); 113235c2221bSDavid Woodhouse return card_flags; 11339c54004eSDavid Woodhouse } 11349c54004eSDavid Woodhouse 11359c54004eSDavid Woodhouse static int psend(struct atm_vcc *vcc, struct sk_buff *skb) 11369c54004eSDavid Woodhouse { 11379c54004eSDavid Woodhouse struct solos_card *card = vcc->dev->dev_data; 11389c54004eSDavid Woodhouse struct pkt_hdr *header; 1139b76811afSDavid Woodhouse int pktlen; 11409c54004eSDavid Woodhouse 1141b76811afSDavid Woodhouse pktlen = skb->len; 1142b76811afSDavid Woodhouse if (pktlen > (BUF_SIZE - sizeof(*header))) { 11439c54004eSDavid Woodhouse dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n"); 11449c54004eSDavid Woodhouse solos_pop(vcc, skb); 11459c54004eSDavid Woodhouse return 0; 11469c54004eSDavid Woodhouse } 11479c54004eSDavid Woodhouse 11489c54004eSDavid Woodhouse if (!skb_clone_writable(skb, sizeof(*header))) { 11499c54004eSDavid Woodhouse int expand_by = 0; 11509c54004eSDavid Woodhouse int ret; 11519c54004eSDavid Woodhouse 11529c54004eSDavid Woodhouse if (skb_headroom(skb) < sizeof(*header)) 11539c54004eSDavid Woodhouse expand_by = sizeof(*header) - skb_headroom(skb); 11549c54004eSDavid Woodhouse 11559c54004eSDavid Woodhouse ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC); 11569c54004eSDavid Woodhouse if (ret) { 11574306cad6SSimon Farnsworth dev_warn(&card->dev->dev, "pskb_expand_head failed.\n"); 11589c54004eSDavid Woodhouse solos_pop(vcc, skb); 11599c54004eSDavid Woodhouse return ret; 11609c54004eSDavid Woodhouse } 11619c54004eSDavid Woodhouse } 11629c54004eSDavid Woodhouse 11639c54004eSDavid Woodhouse header = (void *)skb_push(skb, sizeof(*header)); 11649c54004eSDavid Woodhouse 1165b76811afSDavid Woodhouse /* This does _not_ include the size of the header */ 1166b76811afSDavid Woodhouse header->size = cpu_to_le16(pktlen); 11679c54004eSDavid Woodhouse header->vpi = cpu_to_le16(vcc->vpi); 11689c54004eSDavid Woodhouse header->vci = cpu_to_le16(vcc->vci); 11699c54004eSDavid Woodhouse header->type = cpu_to_le16(PKT_DATA); 11709c54004eSDavid Woodhouse 11719c54004eSDavid Woodhouse fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, vcc); 11729c54004eSDavid Woodhouse 11739c54004eSDavid Woodhouse return 0; 11749c54004eSDavid Woodhouse } 11759c54004eSDavid Woodhouse 11769c54004eSDavid Woodhouse static struct atmdev_ops fpga_ops = { 11779c54004eSDavid Woodhouse .open = popen, 11789c54004eSDavid Woodhouse .close = pclose, 11799c54004eSDavid Woodhouse .ioctl = NULL, 11809c54004eSDavid Woodhouse .getsockopt = NULL, 11819c54004eSDavid Woodhouse .setsockopt = NULL, 11829c54004eSDavid Woodhouse .send = psend, 11839c54004eSDavid Woodhouse .send_oam = NULL, 11849c54004eSDavid Woodhouse .phy_put = NULL, 11859c54004eSDavid Woodhouse .phy_get = NULL, 11869c54004eSDavid Woodhouse .change_qos = NULL, 11879c54004eSDavid Woodhouse .proc_read = NULL, 11889c54004eSDavid Woodhouse .owner = THIS_MODULE 11899c54004eSDavid Woodhouse }; 11909c54004eSDavid Woodhouse 11919c54004eSDavid Woodhouse static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) 11929c54004eSDavid Woodhouse { 1193cd5549e0SDavid Woodhouse int err; 11949c54004eSDavid Woodhouse uint16_t fpga_ver; 11959c54004eSDavid Woodhouse uint8_t major_ver, minor_ver; 11969c54004eSDavid Woodhouse uint32_t data32; 11979c54004eSDavid Woodhouse struct solos_card *card; 11989c54004eSDavid Woodhouse 11999c54004eSDavid Woodhouse card = kzalloc(sizeof(*card), GFP_KERNEL); 12009c54004eSDavid Woodhouse if (!card) 12019c54004eSDavid Woodhouse return -ENOMEM; 12029c54004eSDavid Woodhouse 12039c54004eSDavid Woodhouse card->dev = dev; 1204fa755b9fSDavid Woodhouse init_waitqueue_head(&card->fw_wq); 120501e2ffacSDavid Woodhouse init_waitqueue_head(&card->param_wq); 12069c54004eSDavid Woodhouse 12079c54004eSDavid Woodhouse err = pci_enable_device(dev); 12089c54004eSDavid Woodhouse if (err) { 12099c54004eSDavid Woodhouse dev_warn(&dev->dev, "Failed to enable PCI device\n"); 12109c54004eSDavid Woodhouse goto out; 12119c54004eSDavid Woodhouse } 12129c54004eSDavid Woodhouse 1213e930438cSYang Hongyang err = pci_set_dma_mask(dev, DMA_BIT_MASK(32)); 121490937231SDavid Woodhouse if (err) { 121590937231SDavid Woodhouse dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n"); 121690937231SDavid Woodhouse goto out; 121790937231SDavid Woodhouse } 121890937231SDavid Woodhouse 12199c54004eSDavid Woodhouse err = pci_request_regions(dev, "solos"); 12209c54004eSDavid Woodhouse if (err) { 12219c54004eSDavid Woodhouse dev_warn(&dev->dev, "Failed to request regions\n"); 12229c54004eSDavid Woodhouse goto out; 12239c54004eSDavid Woodhouse } 12249c54004eSDavid Woodhouse 12259c54004eSDavid Woodhouse card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE); 12269c54004eSDavid Woodhouse if (!card->config_regs) { 12279c54004eSDavid Woodhouse dev_warn(&dev->dev, "Failed to ioremap config registers\n"); 122873112f9bSJulia Lawall err = -ENOMEM; 12299c54004eSDavid Woodhouse goto out_release_regions; 12309c54004eSDavid Woodhouse } 12319c54004eSDavid Woodhouse card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE); 12329c54004eSDavid Woodhouse if (!card->buffers) { 12339c54004eSDavid Woodhouse dev_warn(&dev->dev, "Failed to ioremap data buffers\n"); 123473112f9bSJulia Lawall err = -ENOMEM; 12359c54004eSDavid Woodhouse goto out_unmap_config; 12369c54004eSDavid Woodhouse } 12379c54004eSDavid Woodhouse 1238cc3657e1SDavid Woodhouse if (reset) { 1239cc3657e1SDavid Woodhouse iowrite32(1, card->config_regs + FPGA_MODE); 1240cc3657e1SDavid Woodhouse data32 = ioread32(card->config_regs + FPGA_MODE); 12419c54004eSDavid Woodhouse 1242cc3657e1SDavid Woodhouse iowrite32(0, card->config_regs + FPGA_MODE); 1243cc3657e1SDavid Woodhouse data32 = ioread32(card->config_regs + FPGA_MODE); 1244cc3657e1SDavid Woodhouse } 12459c54004eSDavid Woodhouse 12469c54004eSDavid Woodhouse data32 = ioread32(card->config_regs + FPGA_VER); 12479c54004eSDavid Woodhouse fpga_ver = (data32 & 0x0000FFFF); 12489c54004eSDavid Woodhouse major_ver = ((data32 & 0xFF000000) >> 24); 12499c54004eSDavid Woodhouse minor_ver = ((data32 & 0x00FF0000) >> 16); 12504dbedf43SNathan Williams card->fpga_version = FPGA_VERSION(major_ver,minor_ver); 12514dbedf43SNathan Williams if (card->fpga_version > LEGACY_BUFFERS) 12524dbedf43SNathan Williams card->buffer_size = BUF_SIZE; 12534dbedf43SNathan Williams else 12544dbedf43SNathan Williams card->buffer_size = OLD_BUF_SIZE; 12559c54004eSDavid Woodhouse dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", 12569c54004eSDavid Woodhouse major_ver, minor_ver, fpga_ver); 12579c54004eSDavid Woodhouse 12583ce1227cSDavid Woodhouse if (fpga_ver < 37 && (fpga_upgrade || firmware_upgrade || 12593ce1227cSDavid Woodhouse db_fpga_upgrade || db_firmware_upgrade)) { 12603ce1227cSDavid Woodhouse dev_warn(&dev->dev, 12613ce1227cSDavid Woodhouse "FPGA too old; cannot upgrade flash. Use JTAG.\n"); 12623ce1227cSDavid Woodhouse fpga_upgrade = firmware_upgrade = 0; 12633ce1227cSDavid Woodhouse db_fpga_upgrade = db_firmware_upgrade = 0; 12643ce1227cSDavid Woodhouse } 12653ce1227cSDavid Woodhouse 126613af8164SNathan Williams /* Stopped using Atmel flash after 0.03-38 */ 126713af8164SNathan Williams if (fpga_ver < 39) 126813af8164SNathan Williams card->atmel_flash = 1; 126913af8164SNathan Williams else 127013af8164SNathan Williams card->atmel_flash = 0; 127113af8164SNathan Williams 1272152a2a8bSDavid Woodhouse data32 = ioread32(card->config_regs + PORTS); 1273152a2a8bSDavid Woodhouse card->nr_ports = (data32 & 0x000000FF); 1274152a2a8bSDavid Woodhouse 12754dbedf43SNathan Williams if (card->fpga_version >= DMA_SUPPORTED) { 1276b4bd8ad9SDavid Woodhouse pci_set_master(dev); 127790937231SDavid Woodhouse card->using_dma = 1; 1278152a2a8bSDavid Woodhouse if (1) { /* All known FPGA versions so far */ 1279152a2a8bSDavid Woodhouse card->dma_alignment = 3; 1280152a2a8bSDavid Woodhouse card->dma_bounce = kmalloc(card->nr_ports * BUF_SIZE, GFP_KERNEL); 1281152a2a8bSDavid Woodhouse if (!card->dma_bounce) { 1282152a2a8bSDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate DMA bounce buffers\n"); 1283c7bcae46SJulia Lawall err = -ENOMEM; 1284152a2a8bSDavid Woodhouse /* Fallback to MMIO doesn't work */ 1285152a2a8bSDavid Woodhouse goto out_unmap_both; 1286152a2a8bSDavid Woodhouse } 1287152a2a8bSDavid Woodhouse } 12884dbedf43SNathan Williams } else { 12894dbedf43SNathan Williams card->using_dma = 0; 1290eab50f73SDavid Woodhouse /* Set RX empty flag for all ports */ 1291eab50f73SDavid Woodhouse iowrite32(0xF0, card->config_regs + FLAGS_ADDR); 1292eab50f73SDavid Woodhouse } 12939c54004eSDavid Woodhouse 12949c54004eSDavid Woodhouse pci_set_drvdata(dev, card); 1295fa755b9fSDavid Woodhouse 12969c54004eSDavid Woodhouse tasklet_init(&card->tlet, solos_bh, (unsigned long)card); 12979c54004eSDavid Woodhouse spin_lock_init(&card->tx_lock); 12989c54004eSDavid Woodhouse spin_lock_init(&card->tx_queue_lock); 12999c54004eSDavid Woodhouse spin_lock_init(&card->cli_queue_lock); 130001e2ffacSDavid Woodhouse spin_lock_init(&card->param_queue_lock); 130101e2ffacSDavid Woodhouse INIT_LIST_HEAD(&card->param_queue); 13029c54004eSDavid Woodhouse 1303fcd82664SDavid Woodhouse err = request_irq(dev->irq, solos_irq, IRQF_SHARED, 13049c54004eSDavid Woodhouse "solos-pci", card); 1305fa755b9fSDavid Woodhouse if (err) { 13069c54004eSDavid Woodhouse dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq); 1307fa755b9fSDavid Woodhouse goto out_unmap_both; 1308fa755b9fSDavid Woodhouse } 13099c54004eSDavid Woodhouse 13109c54004eSDavid Woodhouse iowrite32(1, card->config_regs + IRQ_EN_ADDR); 13119c54004eSDavid Woodhouse 1312fa755b9fSDavid Woodhouse if (fpga_upgrade) 1313fa755b9fSDavid Woodhouse flash_upgrade(card, 0); 1314fa755b9fSDavid Woodhouse 1315fa755b9fSDavid Woodhouse if (firmware_upgrade) 1316fa755b9fSDavid Woodhouse flash_upgrade(card, 1); 1317fa755b9fSDavid Woodhouse 13184dbedf43SNathan Williams if (db_fpga_upgrade) 13194dbedf43SNathan Williams flash_upgrade(card, 2); 13204dbedf43SNathan Williams 13214dbedf43SNathan Williams if (db_firmware_upgrade) 13224dbedf43SNathan Williams flash_upgrade(card, 3); 13234dbedf43SNathan Williams 1324d9ca676bSDan Williams err = atm_init(card, &dev->dev); 1325fa755b9fSDavid Woodhouse if (err) 1326fa755b9fSDavid Woodhouse goto out_free_irq; 1327fa755b9fSDavid Woodhouse 1328f9baad02SNathan Williams if (card->fpga_version >= DMA_SUPPORTED && 1329f9baad02SNathan Williams sysfs_create_group(&card->dev->dev.kobj, &gpio_attr_group)) 1330f9baad02SNathan Williams dev_err(&card->dev->dev, "Could not register parameter group for GPIOs\n"); 1331f9baad02SNathan Williams 13329c54004eSDavid Woodhouse return 0; 13339c54004eSDavid Woodhouse 1334fa755b9fSDavid Woodhouse out_free_irq: 1335fa755b9fSDavid Woodhouse iowrite32(0, card->config_regs + IRQ_EN_ADDR); 1336fa755b9fSDavid Woodhouse free_irq(dev->irq, card); 1337fa755b9fSDavid Woodhouse tasklet_kill(&card->tlet); 1338fa755b9fSDavid Woodhouse 13399c54004eSDavid Woodhouse out_unmap_both: 1340152a2a8bSDavid Woodhouse kfree(card->dma_bounce); 13419c54004eSDavid Woodhouse pci_iounmap(dev, card->buffers); 13428ae0cfeeSJulia Lawall out_unmap_config: 13438ae0cfeeSJulia Lawall pci_iounmap(dev, card->config_regs); 13449c54004eSDavid Woodhouse out_release_regions: 13459c54004eSDavid Woodhouse pci_release_regions(dev); 13469c54004eSDavid Woodhouse out: 1347bc111d57SJulia Lawall kfree(card); 13489c54004eSDavid Woodhouse return err; 13499c54004eSDavid Woodhouse } 13509c54004eSDavid Woodhouse 1351d9ca676bSDan Williams static int atm_init(struct solos_card *card, struct device *parent) 13529c54004eSDavid Woodhouse { 13539c54004eSDavid Woodhouse int i; 13549c54004eSDavid Woodhouse 13559c54004eSDavid Woodhouse for (i = 0; i < card->nr_ports; i++) { 135687ebb186SDavid Woodhouse struct sk_buff *skb; 135787ebb186SDavid Woodhouse struct pkt_hdr *header; 135887ebb186SDavid Woodhouse 13599c54004eSDavid Woodhouse skb_queue_head_init(&card->tx_queue[i]); 13609c54004eSDavid Woodhouse skb_queue_head_init(&card->cli_queue[i]); 13619c54004eSDavid Woodhouse 1362d9ca676bSDan Williams card->atmdev[i] = atm_dev_register("solos-pci", parent, &fpga_ops, -1, NULL); 13639c54004eSDavid Woodhouse if (!card->atmdev[i]) { 13649c54004eSDavid Woodhouse dev_err(&card->dev->dev, "Could not register ATM device %d\n", i); 13659c54004eSDavid Woodhouse atm_remove(card); 13669c54004eSDavid Woodhouse return -ENODEV; 13679c54004eSDavid Woodhouse } 13689c54004eSDavid Woodhouse if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console)) 13699c54004eSDavid Woodhouse dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i); 1370d057f0a4SDavid Woodhouse if (sysfs_create_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group)) 1371d057f0a4SDavid Woodhouse dev_err(&card->dev->dev, "Could not register parameter group for ATM device %d\n", i); 13729c54004eSDavid Woodhouse 13739c54004eSDavid Woodhouse dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number); 13749c54004eSDavid Woodhouse 13759c54004eSDavid Woodhouse card->atmdev[i]->ci_range.vpi_bits = 8; 13769c54004eSDavid Woodhouse card->atmdev[i]->ci_range.vci_bits = 16; 13779c54004eSDavid Woodhouse card->atmdev[i]->dev_data = card; 13789c54004eSDavid Woodhouse card->atmdev[i]->phy_data = (void *)(unsigned long)i; 1379c031235bSPhilip A. Prindeville atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); 138087ebb186SDavid Woodhouse 1381a1db5c5bSDavid Woodhouse skb = alloc_skb(sizeof(*header), GFP_KERNEL); 138287ebb186SDavid Woodhouse if (!skb) { 138387ebb186SDavid Woodhouse dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); 138487ebb186SDavid Woodhouse continue; 138587ebb186SDavid Woodhouse } 138687ebb186SDavid Woodhouse 138787ebb186SDavid Woodhouse header = (void *)skb_put(skb, sizeof(*header)); 138887ebb186SDavid Woodhouse 138987ebb186SDavid Woodhouse header->size = cpu_to_le16(0); 139087ebb186SDavid Woodhouse header->vpi = cpu_to_le16(0); 139187ebb186SDavid Woodhouse header->vci = cpu_to_le16(0); 139287ebb186SDavid Woodhouse header->type = cpu_to_le16(PKT_STATUS); 139387ebb186SDavid Woodhouse 139487ebb186SDavid Woodhouse fpga_queue(card, i, skb, NULL); 13959c54004eSDavid Woodhouse } 13969c54004eSDavid Woodhouse return 0; 13979c54004eSDavid Woodhouse } 13989c54004eSDavid Woodhouse 13999c54004eSDavid Woodhouse static void atm_remove(struct solos_card *card) 14009c54004eSDavid Woodhouse { 14019c54004eSDavid Woodhouse int i; 14029c54004eSDavid Woodhouse 14039c54004eSDavid Woodhouse for (i = 0; i < card->nr_ports; i++) { 14049c54004eSDavid Woodhouse if (card->atmdev[i]) { 140597d759d3SDavid Woodhouse struct sk_buff *skb; 140697d759d3SDavid Woodhouse 14079c54004eSDavid Woodhouse dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number); 1408c0fe3026SDavid Woodhouse 1409c0fe3026SDavid Woodhouse sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group); 14109c54004eSDavid Woodhouse atm_dev_deregister(card->atmdev[i]); 141197d759d3SDavid Woodhouse 141297d759d3SDavid Woodhouse skb = card->rx_skb[i]; 141397d759d3SDavid Woodhouse if (skb) { 141497d759d3SDavid Woodhouse pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, 141597d759d3SDavid Woodhouse RX_DMA_SIZE, PCI_DMA_FROMDEVICE); 141697d759d3SDavid Woodhouse dev_kfree_skb(skb); 141797d759d3SDavid Woodhouse } 141897d759d3SDavid Woodhouse skb = card->tx_skb[i]; 141997d759d3SDavid Woodhouse if (skb) { 142097d759d3SDavid Woodhouse pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, 142197d759d3SDavid Woodhouse skb->len, PCI_DMA_TODEVICE); 142297d759d3SDavid Woodhouse dev_kfree_skb(skb); 142397d759d3SDavid Woodhouse } 142497d759d3SDavid Woodhouse while ((skb = skb_dequeue(&card->tx_queue[i]))) 142597d759d3SDavid Woodhouse dev_kfree_skb(skb); 142697d759d3SDavid Woodhouse 14279c54004eSDavid Woodhouse } 14289c54004eSDavid Woodhouse } 14299c54004eSDavid Woodhouse } 14309c54004eSDavid Woodhouse 14319c54004eSDavid Woodhouse static void fpga_remove(struct pci_dev *dev) 14329c54004eSDavid Woodhouse { 14339c54004eSDavid Woodhouse struct solos_card *card = pci_get_drvdata(dev); 14349c54004eSDavid Woodhouse 143597d759d3SDavid Woodhouse /* Disable IRQs */ 143697d759d3SDavid Woodhouse iowrite32(0, card->config_regs + IRQ_EN_ADDR); 143797d759d3SDavid Woodhouse 143897d759d3SDavid Woodhouse /* Reset FPGA */ 143997d759d3SDavid Woodhouse iowrite32(1, card->config_regs + FPGA_MODE); 144097d759d3SDavid Woodhouse (void)ioread32(card->config_regs + FPGA_MODE); 14419c54004eSDavid Woodhouse 1442f9baad02SNathan Williams if (card->fpga_version >= DMA_SUPPORTED) 1443f9baad02SNathan Williams sysfs_remove_group(&card->dev->dev.kobj, &gpio_attr_group); 1444f9baad02SNathan Williams 14459c54004eSDavid Woodhouse atm_remove(card); 14469c54004eSDavid Woodhouse 14479c54004eSDavid Woodhouse free_irq(dev->irq, card); 14489c54004eSDavid Woodhouse tasklet_kill(&card->tlet); 14499c54004eSDavid Woodhouse 1450152a2a8bSDavid Woodhouse kfree(card->dma_bounce); 1451152a2a8bSDavid Woodhouse 145297d759d3SDavid Woodhouse /* Release device from reset */ 145397d759d3SDavid Woodhouse iowrite32(0, card->config_regs + FPGA_MODE); 145497d759d3SDavid Woodhouse (void)ioread32(card->config_regs + FPGA_MODE); 145597d759d3SDavid Woodhouse 14569c54004eSDavid Woodhouse pci_iounmap(dev, card->buffers); 14579c54004eSDavid Woodhouse pci_iounmap(dev, card->config_regs); 14589c54004eSDavid Woodhouse 14599c54004eSDavid Woodhouse pci_release_regions(dev); 14609c54004eSDavid Woodhouse pci_disable_device(dev); 14619c54004eSDavid Woodhouse 14629c54004eSDavid Woodhouse kfree(card); 14639c54004eSDavid Woodhouse } 14649c54004eSDavid Woodhouse 14656c44512dSGreg Kroah-Hartman static struct pci_device_id fpga_pci_tbl[] = { 14669c54004eSDavid Woodhouse { 0x10ee, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 14679c54004eSDavid Woodhouse { 0, } 14689c54004eSDavid Woodhouse }; 14699c54004eSDavid Woodhouse 14709c54004eSDavid Woodhouse MODULE_DEVICE_TABLE(pci,fpga_pci_tbl); 14719c54004eSDavid Woodhouse 14729c54004eSDavid Woodhouse static struct pci_driver fpga_driver = { 14739c54004eSDavid Woodhouse .name = "solos", 14749c54004eSDavid Woodhouse .id_table = fpga_pci_tbl, 14759c54004eSDavid Woodhouse .probe = fpga_probe, 14769c54004eSDavid Woodhouse .remove = fpga_remove, 14779c54004eSDavid Woodhouse }; 14789c54004eSDavid Woodhouse 14799c54004eSDavid Woodhouse 14809c54004eSDavid Woodhouse static int __init solos_pci_init(void) 14819c54004eSDavid Woodhouse { 14827ad3eadeSDavid Woodhouse BUILD_BUG_ON(sizeof(struct solos_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); 14837ad3eadeSDavid Woodhouse 14849c54004eSDavid Woodhouse printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); 14859c54004eSDavid Woodhouse return pci_register_driver(&fpga_driver); 14869c54004eSDavid Woodhouse } 14879c54004eSDavid Woodhouse 14889c54004eSDavid Woodhouse static void __exit solos_pci_exit(void) 14899c54004eSDavid Woodhouse { 14909c54004eSDavid Woodhouse pci_unregister_driver(&fpga_driver); 14919c54004eSDavid Woodhouse printk(KERN_INFO "Solos PCI Driver %s Unloaded\n", VERSION); 14929c54004eSDavid Woodhouse } 14939c54004eSDavid Woodhouse 14949c54004eSDavid Woodhouse module_init(solos_pci_init); 14959c54004eSDavid Woodhouse module_exit(solos_pci_exit); 1496