All of lore.kernel.org
 help / color / mirror / Atom feed
* [GIT *] Solos PCI ADSL card update
@ 2009-03-17 17:19 David Woodhouse
  2009-03-17 19:23 ` David Miller
                   ` (30 more replies)
  0 siblings, 31 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 17:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-atm-general, Chas Williams

Please pull from git://git.infradead.org/~dwmw2/solos-2.6.git

This contains a bunch of updates to the Solos PCI driver (full patch
below for review):

David Woodhouse (27):
      solos: Fix length header in FPGA transfers
      solos: Clean up firmware loading code
      solos: Kill global 'opens' count.
      solos: Handle attribute show/store in kernel more sanely
      solos: Add initial list of parameters
      solos: Handle new line status change packets, hook up to ATM layer info
      solos: Kill existing connections on link down event
      solos: Reject non-AAL5 connections.... for now
      solos: Add SNR and Attn to status packet, fix oops on load
      solos: Fix under-allocation of skb size for get/set parameters
      solos: Remove parameter group from sysfs on ATM dev deregister
      solos: First attempt at DMA support
      solos: Tidy up DMA handling a little. Still untested
      solos: Tidy up tx_mask handling for ports which need TX
      solos: Remove unused loopback debug stuff
      solos: Remove IRQF_DISABLED, don't frob IRQ enable on the FPGA in solos_irq()
      solos: Remove superfluous wait_queue_head_t from struct solos_param
      solos: Fix various bugs in status packet handling
      solos: Clean up handling of card->tx_mask a little
      solos: Remove debugging, commented-out test code
      solos: Add 'reset' module parameter to reset the DSL chips on load
      solos: Tidy up status interrupt handling, cope with 'ERROR' status
      solos: Don't clear config registers at startup
      solos: Set RX empty flag at startup only for !dma mode
      solos: Swap upstream/downstream rates in status packet, clean up some more
      solos: Reset device on unload, free pending skbs
      solos: Disable DMA until we have an FPGA update with it actually implemented.

Nathan Williams (1):
      solos: Automatically determine number of ports

Simon Farnsworth (2):
      solos: Slight debugging improvements
      solos: FPGA and firmware update support.

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 72fc0f7..bc3079d 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -9,6 +9,7 @@
  *
  * Authors: Nathan Williams <nathan@traverse.com.au>
  *          David Woodhouse <dwmw2@infradead.org>
+ *          Treker Chen <treker@xrio.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -36,8 +37,11 @@
 #include <linux/sysfs.h>
 #include <linux/device.h>
 #include <linux/kobject.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+#include <linux/swab.h>
 
-#define VERSION "0.04"
+#define VERSION "0.07"
 #define PTAG "solos-pci"
 
 #define CONFIG_RAM_SIZE	128
@@ -45,16 +49,31 @@
 #define IRQ_EN_ADDR	0x78
 #define FPGA_VER	0x74
 #define IRQ_CLEAR	0x70
-#define BUG_FLAG	0x6C
+#define WRITE_FLASH	0x6C
+#define PORTS		0x68
+#define FLASH_BLOCK	0x64
+#define FLASH_BUSY	0x60
+#define FPGA_MODE	0x5C
+#define FLASH_MODE	0x58
+#define TX_DMA_ADDR(port)	(0x40 + (4 * (port)))
+#define RX_DMA_ADDR(port)	(0x30 + (4 * (port)))
 
 #define DATA_RAM_SIZE	32768
 #define BUF_SIZE	4096
+#define FPGA_PAGE	528 /* FPGA flash page size*/
+#define SOLOS_PAGE	512 /* Solos flash page size*/
+#define FPGA_BLOCK	(FPGA_PAGE * 8) /* FPGA flash block size*/
+#define SOLOS_BLOCK	(SOLOS_PAGE * 8) /* Solos flash block size*/
 
 #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
 #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)
 
-static int debug = 0;
+#define RX_DMA_SIZE	2048
+
+static int reset = 0;
 static int atmdebug = 0;
+static int firmware_upgrade = 0;
+static int fpga_upgrade = 0;
 
 struct pkt_hdr {
 	__le16 size;
@@ -63,23 +82,48 @@ struct pkt_hdr {
 	__le16 type;
 };
 
+struct solos_skb_cb {
+	struct atm_vcc *vcc;
+	uint32_t dma_addr;
+};
+
+
+#define SKB_CB(skb)		((struct solos_skb_cb *)skb->cb)
+
 #define PKT_DATA	0
 #define PKT_COMMAND	1
 #define PKT_POPEN	3
 #define PKT_PCLOSE	4
+#define PKT_STATUS	5
 
 struct solos_card {
 	void __iomem *config_regs;
 	void __iomem *buffers;
 	int nr_ports;
+	int tx_mask;
 	struct pci_dev *dev;
 	struct atm_dev *atmdev[4];
 	struct tasklet_struct tlet;
 	spinlock_t tx_lock;
 	spinlock_t tx_queue_lock;
 	spinlock_t cli_queue_lock;
+	spinlock_t param_queue_lock;
+	struct list_head param_queue;
 	struct sk_buff_head tx_queue[4];
 	struct sk_buff_head cli_queue[4];
+	struct sk_buff *tx_skb[4];
+	struct sk_buff *rx_skb[4];
+	wait_queue_head_t param_wq;
+	wait_queue_head_t fw_wq;
+	int using_dma;
+};
+
+
+struct solos_param {
+	struct list_head list;
+	pid_t pid;
+	int port;
+	struct sk_buff *response;
 };
 
 #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
@@ -88,19 +132,22 @@ MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
 MODULE_DESCRIPTION("Solos PCI driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(debug, "Enable Loopback");
+MODULE_PARM_DESC(reset, "Reset Solos chips on startup");
 MODULE_PARM_DESC(atmdebug, "Print ATM data");
-module_param(debug, int, 0444);
-module_param(atmdebug, int, 0444);
-
-static int opens;
+MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
+MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
+module_param(reset, int, 0444);
+module_param(atmdebug, int, 0644);
+module_param(firmware_upgrade, int, 0444);
+module_param(fpga_upgrade, int, 0444);
 
 static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc);
-static int fpga_tx(struct solos_card *);
+static uint32_t fpga_tx(struct solos_card *);
 static irqreturn_t solos_irq(int irq, void *dev_id);
 static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
 static int list_vccs(int vci);
+static void release_vccs(struct atm_dev *dev);
 static int atm_init(struct solos_card *);
 static void atm_remove(struct solos_card *);
 static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
@@ -115,6 +162,264 @@ static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb)
                 dev_kfree_skb_any(skb);
 }
 
+static ssize_t solos_param_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+	struct solos_card *card = atmdev->dev_data;
+	struct solos_param prm;
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+	int buflen;
+
+	buflen = strlen(attr->attr.name) + 10;
+
+	skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL);
+	if (!skb) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n");
+		return -ENOMEM;
+	}
+
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	buflen = snprintf((void *)&header[1], buflen - 1,
+			  "L%05d\n%s\n", current->pid, attr->attr.name);
+	skb_put(skb, buflen);
+
+	header->size = cpu_to_le16(buflen);
+	header->vpi = cpu_to_le16(0);
+	header->vci = cpu_to_le16(0);
+	header->type = cpu_to_le16(PKT_COMMAND);
+
+	prm.pid = current->pid;
+	prm.response = NULL;
+	prm.port = SOLOS_CHAN(atmdev);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_add(&prm.list, &card->param_queue);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	fpga_queue(card, prm.port, skb, NULL);
+
+	wait_event_timeout(card->param_wq, prm.response, 5 * HZ);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_del(&prm.list);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	if (!prm.response)
+		return -EIO;
+
+	buflen = prm.response->len;
+	memcpy(buf, prm.response->data, buflen);
+	kfree_skb(prm.response);
+
+	return buflen;
+}
+
+static ssize_t solos_param_store(struct device *dev, struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+	struct solos_card *card = atmdev->dev_data;
+	struct solos_param prm;
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+	int buflen;
+	ssize_t ret;
+
+	buflen = strlen(attr->attr.name) + 11 + count;
+
+	skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL);
+	if (!skb) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n");
+		return -ENOMEM;
+	}
+
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	buflen = snprintf((void *)&header[1], buflen - 1,
+			  "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf);
+
+	skb_put(skb, buflen);
+	header->size = cpu_to_le16(buflen);
+	header->vpi = cpu_to_le16(0);
+	header->vci = cpu_to_le16(0);
+	header->type = cpu_to_le16(PKT_COMMAND);
+
+	prm.pid = current->pid;
+	prm.response = NULL;
+	prm.port = SOLOS_CHAN(atmdev);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_add(&prm.list, &card->param_queue);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	fpga_queue(card, prm.port, skb, NULL);
+
+	wait_event_timeout(card->param_wq, prm.response, 5 * HZ);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_del(&prm.list);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	skb = prm.response;
+
+	if (!skb)
+		return -EIO;
+
+	buflen = skb->len;
+
+	/* Sometimes it has a newline, sometimes it doesn't. */
+	if (skb->data[buflen - 1] == '\n')
+		buflen--;
+
+	if (buflen == 2 && !strncmp(skb->data, "OK", 2))
+		ret = count;
+	else if (buflen == 5 && !strncmp(skb->data, "ERROR", 5))
+		ret = -EIO;
+	else {
+		/* We know we have enough space allocated for this; we allocated 
+		   it ourselves */
+		skb->data[buflen] = 0;
+	
+		dev_warn(&card->dev->dev, "Unexpected parameter response: '%s'\n",
+			 skb->data);
+		ret = -EIO;
+	}
+	kfree_skb(skb);
+
+	return ret;
+}
+
+static char *next_string(struct sk_buff *skb)
+{
+	int i = 0;
+	char *this = skb->data;
+	
+	for (i = 0; i < skb->len; i++) {
+		if (this[i] == '\n') {
+			this[i] = 0;
+			skb_pull(skb, i + 1);
+			return this;
+		}
+		if (!isprint(this[i]))
+			return NULL;
+	}
+	return NULL;
+}
+
+/*
+ * Status packet has fields separated by \n, starting with a version number
+ * for the information therein. Fields are....
+ *
+ *     packet version
+ *     RxBitRate	(version >= 1)
+ *     TxBitRate	(version >= 1)
+ *     State		(version >= 1)
+ *     LocalSNRMargin	(version >= 1)
+ *     LocalLineAttn	(version >= 1)
+ */       
+static int process_status(struct solos_card *card, int port, struct sk_buff *skb)
+{
+	char *str, *end, *state_str, *snr, *attn;
+	int ver, rate_up, rate_down;
+
+	if (!card->atmdev[port])
+		return -ENODEV;
+
+	str = next_string(skb);
+	if (!str)
+		return -EIO;
+
+	ver = simple_strtol(str, NULL, 10);
+	if (ver < 1) {
+		dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n",
+			 ver);
+		return -EIO;
+	}
+
+	str = next_string(skb);
+	if (!str)
+		return -EIO;
+	if (!strcmp(str, "ERROR")) {
+		dev_dbg(&card->dev->dev, "Status packet indicated Solos error on port %d (starting up?)\n",
+			 port);
+		return 0;
+	}
+
+	rate_down = simple_strtol(str, &end, 10);
+	if (*end)
+		return -EIO;
+
+	str = next_string(skb);
+	if (!str)
+		return -EIO;
+	rate_up = simple_strtol(str, &end, 10);
+	if (*end)
+		return -EIO;
+
+	state_str = next_string(skb);
+	if (!state_str)
+		return -EIO;
+
+	/* Anything but 'Showtime' is down */
+	if (strcmp(state_str, "Showtime")) {
+		card->atmdev[port]->signal = ATM_PHY_SIG_LOST;
+		release_vccs(card->atmdev[port]);
+		dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
+		return 0;
+	}
+
+	snr = next_string(skb);
+	if (!str)
+		return -EIO;
+	attn = next_string(skb);
+	if (!attn)
+		return -EIO;
+
+	dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n",
+		 port, state_str, rate_down/1000, rate_up/1000,
+		 snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
+	
+	card->atmdev[port]->link_rate = rate_down / 424;
+	card->atmdev[port]->signal = ATM_PHY_SIG_FOUND;
+
+	return 0;
+}
+
+static int process_command(struct solos_card *card, int port, struct sk_buff *skb)
+{
+	struct solos_param *prm;
+	unsigned long flags;
+	int cmdpid;
+	int found = 0;
+
+	if (skb->len < 7)
+		return 0;
+
+	if (skb->data[0] != 'L'    || !isdigit(skb->data[1]) ||
+	    !isdigit(skb->data[2]) || !isdigit(skb->data[3]) ||
+	    !isdigit(skb->data[4]) || !isdigit(skb->data[5]) ||
+	    skb->data[6] != '\n')
+		return 0;
+
+	cmdpid = simple_strtol(&skb->data[1], NULL, 10);
+
+	spin_lock_irqsave(&card->param_queue_lock, flags);
+	list_for_each_entry(prm, &card->param_queue, list) {
+		if (prm->port == port && prm->pid == cmdpid) {
+			prm->response = skb;
+			skb_pull(skb, 7);
+			wake_up(&card->param_wq);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&card->param_queue_lock, flags);
+	return found;
+}
+
 static ssize_t console_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
@@ -140,8 +445,6 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_
 	struct sk_buff *skb;
 	struct pkt_hdr *header;
 
-//	dev_dbg(&card->dev->dev, "size: %d\n", size);
-
 	if (size > (BUF_SIZE - sizeof(*header))) {
 		dev_dbg(&card->dev->dev, "Command is too big.  Dropping request\n");
 		return 0;
@@ -180,82 +483,181 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(console, 0644, console_show, console_store);
 
+
+#define SOLOS_ATTR_RO(x) static DEVICE_ATTR(x, 0444, solos_param_show, NULL);
+#define SOLOS_ATTR_RW(x) static DEVICE_ATTR(x, 0644, solos_param_show, solos_param_store);
+
+#include "solos-attrlist.c"
+
+#undef SOLOS_ATTR_RO
+#undef SOLOS_ATTR_RW
+
+#define SOLOS_ATTR_RO(x) &dev_attr_##x.attr,
+#define SOLOS_ATTR_RW(x) &dev_attr_##x.attr,
+
+static struct attribute *solos_attrs[] = {
+#include "solos-attrlist.c"
+	NULL
+};
+
+static struct attribute_group solos_attr_group = {
+	.attrs = solos_attrs,
+	.name = "parameters",
+};
+
+static int flash_upgrade(struct solos_card *card, int chip)
+{
+	const struct firmware *fw;
+	const char *fw_name;
+	uint32_t data32 = 0;
+	int blocksize = 0;
+	int numblocks = 0;
+	int offset;
+
+	if (chip == 0) {
+		fw_name = "solos-FPGA.bin";
+		blocksize = FPGA_BLOCK;
+	} else {
+		fw_name = "solos-Firmware.bin";
+		blocksize = SOLOS_BLOCK;
+	}
+
+	if (request_firmware(&fw, fw_name, &card->dev->dev))
+		return -ENOENT;
+
+	dev_info(&card->dev->dev, "Flash upgrade starting\n");
+
+	numblocks = fw->size / blocksize;
+	dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size);
+	dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
+	
+	dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
+	iowrite32(1, card->config_regs + FPGA_MODE);
+	data32 = ioread32(card->config_regs + FPGA_MODE); 
+
+	/* Set mode to Chip Erase */
+	dev_info(&card->dev->dev, "Set FPGA Flash mode to %s Chip Erase\n",
+		 chip?"Solos":"FPGA");
+	iowrite32((chip * 2), card->config_regs + FLASH_MODE);
+
+
+	iowrite32(1, card->config_regs + WRITE_FLASH);
+	wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
+
+	for (offset = 0; offset < fw->size; offset += blocksize) {
+		int i;
+
+		/* Clear write flag */
+		iowrite32(0, card->config_regs + WRITE_FLASH);
+
+		/* Set mode to Block Write */
+		/* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */
+		iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE);
+
+		/* Copy block to buffer, swapping each 16 bits */
+		for(i = 0; i < blocksize; i += 4) {
+			uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i));
+			iowrite32(word, RX_BUF(card, 3) + i);
+		}
+
+		/* Specify block number and then trigger flash write */
+		iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK);
+		iowrite32(1, card->config_regs + WRITE_FLASH);
+		wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
+	}
+
+	release_firmware(fw);
+	iowrite32(0, card->config_regs + WRITE_FLASH);
+	iowrite32(0, card->config_regs + FPGA_MODE);
+	iowrite32(0, card->config_regs + FLASH_MODE);
+	dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
+	return 0;
+}
+
 static irqreturn_t solos_irq(int irq, void *dev_id)
 {
 	struct solos_card *card = dev_id;
 	int handled = 1;
 
-	//ACK IRQ
 	iowrite32(0, card->config_regs + IRQ_CLEAR);
-	//Disable IRQs from FPGA
-	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
-	/* If we only do it when the device is open, we lose console
-	   messages */
-	if (1 || opens)
+	/* If we're up and running, just kick the tasklet to process TX/RX */
+	if (card->atmdev[0])
 		tasklet_schedule(&card->tlet);
+	else
+		wake_up(&card->fw_wq);
 
-	//Enable IRQs from FPGA
-	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 	return IRQ_RETVAL(handled);
 }
 
 void solos_bh(unsigned long card_arg)
 {
 	struct solos_card *card = (void *)card_arg;
-	int port;
 	uint32_t card_flags;
-	uint32_t tx_mask;
 	uint32_t rx_done = 0;
+	int port;
 
-	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
-
-	/* The TX bits are set if the channel is busy; clear if not. We want to
-	   invoke fpga_tx() unless _all_ the bits for active channels are set */
-	tx_mask = (1 << card->nr_ports) - 1;
-	if ((card_flags & tx_mask) != tx_mask)
-		fpga_tx(card);
+	/*
+	 * Since fpga_tx() is going to need to read the flags under its lock,
+	 * it can return them to us so that we don't have to hit PCI MMIO
+	 * again for the same information
+	 */
+	card_flags = fpga_tx(card);
 
 	for (port = 0; port < card->nr_ports; port++) {
 		if (card_flags & (0x10 << port)) {
-			struct pkt_hdr header;
+			struct pkt_hdr _hdr, *header;
 			struct sk_buff *skb;
 			struct atm_vcc *vcc;
 			int size;
 
-			rx_done |= 0x10 << port;
+			if (card->using_dma) {
+				skb = card->rx_skb[port];
+				card->rx_skb[port] = NULL;
 
-			memcpy_fromio(&header, RX_BUF(card, port), sizeof(header));
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+						 RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
 
-			size = le16_to_cpu(header.size);
+				header = (void *)skb->data;
+				size = le16_to_cpu(header->size);
+				skb_put(skb, size + sizeof(*header));
+				skb_pull(skb, sizeof(*header));
+			} else {
+				header = &_hdr;
 
-			skb = alloc_skb(size, GFP_ATOMIC);
-			if (!skb) {
-				if (net_ratelimit())
-					dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
-				continue;
-			}
+				rx_done |= 0x10 << port;
+
+				memcpy_fromio(header, RX_BUF(card, port), sizeof(*header));
 
-			memcpy_fromio(skb_put(skb, size),
-				      RX_BUF(card, port) + sizeof(header),
-				      size);
+				size = le16_to_cpu(header->size);
 
+				skb = alloc_skb(size + 1, GFP_ATOMIC);
+				if (!skb) {
+					if (net_ratelimit())
+						dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+					continue;
+				}
+
+				memcpy_fromio(skb_put(skb, size),
+					      RX_BUF(card, port) + sizeof(*header),
+					      size);
+			}
 			if (atmdebug) {
 				dev_info(&card->dev->dev, "Received: device %d\n", port);
 				dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
-					 size, le16_to_cpu(header.vpi),
-					 le16_to_cpu(header.vci));
+					 size, le16_to_cpu(header->vpi),
+					 le16_to_cpu(header->vci));
 				print_buffer(skb);
 			}
 
-			switch (le16_to_cpu(header.type)) {
+			switch (le16_to_cpu(header->type)) {
 			case PKT_DATA:
-				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi),
-					       le16_to_cpu(header.vci));
+				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi),
+					       le16_to_cpu(header->vci));
 				if (!vcc) {
 					if (net_ratelimit())
 						dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n",
-							 le16_to_cpu(header.vci), le16_to_cpu(header.vpi),
+							 le16_to_cpu(header->vci), le16_to_cpu(header->vpi),
 							 port);
 					continue;
 				}
@@ -264,19 +666,50 @@ void solos_bh(unsigned long card_arg)
 				atomic_inc(&vcc->stats->rx);
 				break;
 
+			case PKT_STATUS:
+				if (process_status(card, port, skb) &&
+				    net_ratelimit()) {
+					dev_warn(&card->dev->dev, "Bad status packet of %d bytes on port %d:\n", skb->len, port);
+					print_buffer(skb);
+				}
+				dev_kfree_skb_any(skb);
+				break;
+
 			case PKT_COMMAND:
 			default: /* FIXME: Not really, surely? */
+				if (process_command(card, port, skb))
+					break;
 				spin_lock(&card->cli_queue_lock);
 				if (skb_queue_len(&card->cli_queue[port]) > 10) {
 					if (net_ratelimit())
 						dev_warn(&card->dev->dev, "Dropping console response on port %d\n",
 							 port);
+					dev_kfree_skb_any(skb);
 				} else
 					skb_queue_tail(&card->cli_queue[port], skb);
 				spin_unlock(&card->cli_queue_lock);
 				break;
 			}
 		}
+		/* Allocate RX skbs for any ports which need them */
+		if (card->using_dma && card->atmdev[port] &&
+		    !card->rx_skb[port]) {
+			struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC);
+			if (skb) {
+				SKB_CB(skb)->dma_addr =
+					pci_map_single(card->dev, skb->data,
+						       RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+				iowrite32(SKB_CB(skb)->dma_addr,
+					  card->config_regs + RX_DMA_ADDR(port));
+				card->rx_skb[port] = skb;
+			} else {
+				if (net_ratelimit())
+					dev_warn(&card->dev->dev, "Failed to allocate RX skb");
+
+				/* We'll have to try again later */
+				tasklet_schedule(&card->tlet);
+			}
+		}
 	}
 	if (rx_done)
 		iowrite32(rx_done, card->config_regs + FLAGS_ADDR);
@@ -326,7 +759,7 @@ static int list_vccs(int vci)
 			       vcc->vci);
 		}
 	} else {
-		for(i=0; i<32; i++){
+		for(i = 0; i < VCC_HTABLE_SIZE; i++){
 			head = &vcc_hash[i];
 			sk_for_each(s, node, head) {
 				num_found ++;
@@ -342,6 +775,28 @@ static int list_vccs(int vci)
 	return num_found;
 }
 
+static void release_vccs(struct atm_dev *dev)
+{
+        int i;
+
+        write_lock_irq(&vcc_sklist_lock);
+        for (i = 0; i < VCC_HTABLE_SIZE; i++) {
+                struct hlist_head *head = &vcc_hash[i];
+                struct hlist_node *node, *tmp;
+                struct sock *s;
+                struct atm_vcc *vcc;
+
+                sk_for_each_safe(s, node, tmp, head) {
+                        vcc = atm_sk(s);
+                        if (vcc->dev == dev) {
+                                vcc_release_async(vcc, -EPIPE);
+                                sk_del_node_init(s);
+                        }
+                }
+        }
+        write_unlock_irq(&vcc_sklist_lock);
+}
+
 
 static int popen(struct atm_vcc *vcc)
 {
@@ -349,6 +804,12 @@ static int popen(struct atm_vcc *vcc)
 	struct sk_buff *skb;
 	struct pkt_hdr *header;
 
+	if (vcc->qos.aal != ATM_AAL5) {
+		dev_warn(&card->dev->dev, "Unsupported ATM type %d\n",
+			 vcc->qos.aal);
+		return -EINVAL;
+	}
+
 	skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
 	if (!skb && net_ratelimit()) {
 		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
@@ -356,22 +817,17 @@ static int popen(struct atm_vcc *vcc)
 	}
 	header = (void *)skb_put(skb, sizeof(*header));
 
-	header->size = cpu_to_le16(sizeof(*header));
+	header->size = cpu_to_le16(0);
 	header->vpi = cpu_to_le16(vcc->vpi);
 	header->vci = cpu_to_le16(vcc->vci);
 	header->type = cpu_to_le16(PKT_POPEN);
 
 	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
-//	dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-	set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci
+	set_bit(ATM_VF_ADDR, &vcc->flags);
 	set_bit(ATM_VF_READY, &vcc->flags);
 	list_vccs(0);
 
-	if (!opens)
-		iowrite32(1, card->config_regs + IRQ_EN_ADDR);
-
-	opens++; //count open PVCs
 
 	return 0;
 }
@@ -389,17 +845,13 @@ static void pclose(struct atm_vcc *vcc)
 	}
 	header = (void *)skb_put(skb, sizeof(*header));
 
-	header->size = cpu_to_le16(sizeof(*header));
+	header->size = cpu_to_le16(0);
 	header->vpi = cpu_to_le16(vcc->vpi);
 	header->vci = cpu_to_le16(vcc->vci);
 	header->type = cpu_to_le16(PKT_PCLOSE);
 
 	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
-//	dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-	if (!--opens)
-		iowrite32(0, card->config_regs + IRQ_EN_ADDR);
-
 	clear_bit(ATM_VF_ADDR, &vcc->flags);
 	clear_bit(ATM_VF_READY, &vcc->flags);
 
@@ -439,22 +891,26 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc)
 {
 	int old_len;
+	unsigned long flags;
 
-	*(void **)skb->cb = vcc;
+	SKB_CB(skb)->vcc = vcc;
 
-	spin_lock(&card->tx_queue_lock);
+	spin_lock_irqsave(&card->tx_queue_lock, flags);
 	old_len = skb_queue_len(&card->tx_queue[port]);
 	skb_queue_tail(&card->tx_queue[port], skb);
-	spin_unlock(&card->tx_queue_lock);
+	if (!old_len)
+		card->tx_mask |= (1 << port);
+	spin_unlock_irqrestore(&card->tx_queue_lock, flags);
 
-	/* If TX might need to be started, do so */
+	/* Theoretically we could just schedule the tasklet here, but
+	   that introduces latency we don't want -- it's noticeable */
 	if (!old_len)
 		fpga_tx(card);
 }
 
-static int fpga_tx(struct solos_card *card)
+static uint32_t fpga_tx(struct solos_card *card)
 {
-	uint32_t tx_pending;
+	uint32_t tx_pending, card_flags;
 	uint32_t tx_started = 0;
 	struct sk_buff *skb;
 	struct atm_vcc *vcc;
@@ -462,69 +918,77 @@ static int fpga_tx(struct solos_card *card)
 	unsigned long flags;
 
 	spin_lock_irqsave(&card->tx_lock, flags);
-
-	tx_pending = ioread32(card->config_regs + FLAGS_ADDR);
-
-	dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
-
-	for (port = 0; port < card->nr_ports; port++) {
-		if (!(tx_pending & (1 << port))) {
+	
+	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
+	/*
+	 * The queue lock is required for _writing_ to tx_mask, but we're
+	 * OK to read it here without locking. The only potential update
+	 * that we could race with is in fpga_queue() where it sets a bit
+	 * for a new port... but it's going to call this function again if
+	 * it's doing that, anyway.
+	 */
+	tx_pending = card->tx_mask & ~card_flags;
+
+	for (port = 0; tx_pending; tx_pending >>= 1, port++) {
+		if (tx_pending & 1) {
+			struct sk_buff *oldskb = card->tx_skb[port];
+			if (oldskb)
+				pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
+						 oldskb->len, PCI_DMA_TODEVICE);
 
 			spin_lock(&card->tx_queue_lock);
 			skb = skb_dequeue(&card->tx_queue[port]);
+			if (!skb)
+				card->tx_mask &= ~(1 << port);
 			spin_unlock(&card->tx_queue_lock);
 
-			if (!skb)
+			if (skb && !card->using_dma) {
+				memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
+				tx_started |= 1 << port;
+				oldskb = skb; /* We're done with this skb already */
+			} else if (skb && card->using_dma) {
+				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
+								       skb->len, PCI_DMA_TODEVICE);
+				iowrite32(SKB_CB(skb)->dma_addr,
+					  card->config_regs + TX_DMA_ADDR(port));
+			}
+
+			if (!oldskb)
 				continue;
 
+			/* Clean up and free oldskb now it's gone */
 			if (atmdebug) {
 				dev_info(&card->dev->dev, "Transmitted: port %d\n",
 					 port);
-				print_buffer(skb);
+				print_buffer(oldskb);
 			}
-			memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
 
-			vcc = *(void **)skb->cb;
+			vcc = SKB_CB(oldskb)->vcc;
 
 			if (vcc) {
 				atomic_inc(&vcc->stats->tx);
-				solos_pop(vcc, skb);
+				solos_pop(vcc, oldskb);
 			} else
-				dev_kfree_skb_irq(skb);
+				dev_kfree_skb_irq(oldskb);
 
-			tx_started |= 1 << port; //Set TX full flag
 		}
 	}
+	/* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */
 	if (tx_started)
 		iowrite32(tx_started, card->config_regs + FLAGS_ADDR);
 
 	spin_unlock_irqrestore(&card->tx_lock, flags);
-	return 0;
+	return card_flags;
 }
 
 static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 {
 	struct solos_card *card = vcc->dev->dev_data;
-	struct sk_buff *skb2 = NULL;
 	struct pkt_hdr *header;
+	int pktlen;
 
-	//dev_dbg(&card->dev->dev, "psend called.\n");
-	//dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci);
-
-	if (debug) {
-		skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC);
-		if (skb2) {
-			memcpy(skb2->data, skb->data, skb->len);
-			skb_put(skb2, skb->len);
-			vcc->push(vcc, skb2);
-			atomic_inc(&vcc->stats->rx);
-		}
-		atomic_inc(&vcc->stats->tx);
-		solos_pop(vcc, skb);
-		return 0;
-	}
-
-	if (skb->len > (BUF_SIZE - sizeof(*header))) {
+	pktlen = skb->len;
+	if (pktlen > (BUF_SIZE - sizeof(*header))) {
 		dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n");
 		solos_pop(vcc, skb);
 		return 0;
@@ -539,6 +1003,7 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 
 		ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC);
 		if (ret) {
+			dev_warn(&card->dev->dev, "pskb_expand_head failed.\n");
 			solos_pop(vcc, skb);
 			return ret;
 		}
@@ -546,7 +1011,8 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 
 	header = (void *)skb_push(skb, sizeof(*header));
 
-	header->size = cpu_to_le16(skb->len);
+	/* This does _not_ include the size of the header */
+	header->size = cpu_to_le16(pktlen);
 	header->vpi = cpu_to_le16(vcc->vpi);
 	header->vci = cpu_to_le16(vcc->vci);
 	header->type = cpu_to_le16(PKT_DATA);
@@ -573,20 +1039,19 @@ static struct atmdev_ops fpga_ops = {
 
 static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	int err, i;
+	int err;
 	uint16_t fpga_ver;
 	uint8_t major_ver, minor_ver;
 	uint32_t data32;
 	struct solos_card *card;
 
-	if (debug)
-		return 0;
-
 	card = kzalloc(sizeof(*card), GFP_KERNEL);
 	if (!card)
 		return -ENOMEM;
 
 	card->dev = dev;
+	init_waitqueue_head(&card->fw_wq);
+	init_waitqueue_head(&card->param_wq);
 
 	err = pci_enable_device(dev);
 	if (err) {
@@ -594,6 +1059,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto out;
 	}
 
+	err = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+	if (err) {
+		dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n");
+		goto out;
+	}
+
 	err = pci_request_regions(dev, "solos");
 	if (err) {
 		dev_warn(&dev->dev, "Failed to request regions\n");
@@ -611,17 +1082,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto out_unmap_config;
 	}
 
-//	for(i=0;i<64 ;i+=4){
-//		data32=ioread32(card->buffers + i);
-//		dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32);
-//	}
-
-	//Fill Config Mem with zeros
-	for(i = 0; i < 128; i += 4)
-		iowrite32(0, card->config_regs + i);
+	if (reset) {
+		iowrite32(1, card->config_regs + FPGA_MODE);
+		data32 = ioread32(card->config_regs + FPGA_MODE); 
 
-	//Set RX empty flags
-	iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
+		iowrite32(0, card->config_regs + FPGA_MODE);
+		data32 = ioread32(card->config_regs + FPGA_MODE); 
+	}
 
 	data32 = ioread32(card->config_regs + FPGA_VER);
 	fpga_ver = (data32 & 0x0000FFFF);
@@ -630,55 +1097,53 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
 		 major_ver, minor_ver, fpga_ver);
 
-	card->nr_ports = 2; /* FIXME: Detect daughterboard */
+	if (0 && fpga_ver > 27)
+		card->using_dma = 1;
+	else {
+		/* Set RX empty flag for all ports */
+		iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
+	}
 
-	err = atm_init(card);
-	if (err)
-		goto out_unmap_both;
+	data32 = ioread32(card->config_regs + PORTS);
+	card->nr_ports = (data32 & 0x000000FF);
 
 	pci_set_drvdata(dev, card);
+
 	tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
 	spin_lock_init(&card->tx_lock);
 	spin_lock_init(&card->tx_queue_lock);
 	spin_lock_init(&card->cli_queue_lock);
-/*
-	// Set Loopback mode
-	data32 = 0x00010000;
-	iowrite32(data32,card->config_regs + FLAGS_ADDR);
-*/
-/*
-	// Fill Buffers with zeros
-	for (i = 0; i < BUF_SIZE * 8; i += 4)
-		iowrite32(0, card->buffers + i);
-*/
-/*
-	for(i = 0; i < (BUF_SIZE * 1); i += 4)
-		iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE));
-	for(i = 0; i < (BUF_SIZE * 1); i += 4)
-		iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE));
-
-	// Read Config Memory
-	printk(KERN_DEBUG "Reading Config MEM\n");
-	i = 0;
-	for(i = 0; i < 16; i++) {
-		data32=ioread32(card->buffers + i*(BUF_SIZE/2));
-		printk(KERN_ALERT "Addr: %lX Data: %08lX\n",
-		       (unsigned long)(addr_start + i*(BUF_SIZE/2)),
-		       (unsigned long)data32);
-	}
-*/
-	//dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq);
-	err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED,
+	spin_lock_init(&card->param_queue_lock);
+	INIT_LIST_HEAD(&card->param_queue);
+
+	err = request_irq(dev->irq, solos_irq, IRQF_SHARED,
 			  "solos-pci", card);
-	if (err)
+	if (err) {
 		dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq);
+		goto out_unmap_both;
+	}
 
-	// Enable IRQs
 	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 
+	if (fpga_upgrade)
+		flash_upgrade(card, 0);
+
+	if (firmware_upgrade)
+		flash_upgrade(card, 1);
+
+	err = atm_init(card);
+	if (err)
+		goto out_free_irq;
+
 	return 0;
 
+ out_free_irq:
+	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+	free_irq(dev->irq, card);
+	tasklet_kill(&card->tlet);
+	
  out_unmap_both:
+	pci_set_drvdata(dev, NULL);
 	pci_iounmap(dev, card->config_regs);
  out_unmap_config:
 	pci_iounmap(dev, card->buffers);
@@ -692,9 +1157,10 @@ static int atm_init(struct solos_card *card)
 {
 	int i;
 
-	opens = 0;
-
 	for (i = 0; i < card->nr_ports; i++) {
+		struct sk_buff *skb;
+		struct pkt_hdr *header;
+
 		skb_queue_head_init(&card->tx_queue[i]);
 		skb_queue_head_init(&card->cli_queue[i]);
 
@@ -706,6 +1172,8 @@ static int atm_init(struct solos_card *card)
 		}
 		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console))
 			dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i);
+		if (sysfs_create_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group))
+			dev_err(&card->dev->dev, "Could not register parameter group for ATM device %d\n", i);
 
 		dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number);
 
@@ -713,6 +1181,22 @@ static int atm_init(struct solos_card *card)
 		card->atmdev[i]->ci_range.vci_bits = 16;
 		card->atmdev[i]->dev_data = card;
 		card->atmdev[i]->phy_data = (void *)(unsigned long)i;
+		card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN;
+
+		skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
+		if (!skb) {
+			dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n");
+			continue;
+		}
+
+		header = (void *)skb_put(skb, sizeof(*header));
+
+		header->size = cpu_to_le16(0);
+		header->vpi = cpu_to_le16(0);
+		header->vci = cpu_to_le16(0);
+		header->type = cpu_to_le16(PKT_STATUS);
+
+		fpga_queue(card, i, skb, NULL);
 	}
 	return 0;
 }
@@ -723,8 +1207,28 @@ static void atm_remove(struct solos_card *card)
 
 	for (i = 0; i < card->nr_ports; i++) {
 		if (card->atmdev[i]) {
+			struct sk_buff *skb;
+
 			dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number);
+
+			sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group);
 			atm_dev_deregister(card->atmdev[i]);
+
+			skb = card->rx_skb[i];
+			if (skb) {
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+						 RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(skb);
+			}
+			skb = card->tx_skb[i];
+			if (skb) {
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb(skb);
+			}
+			while ((skb = skb_dequeue(&card->tx_queue[i])))
+				dev_kfree_skb(skb);
+ 
 		}
 	}
 }
@@ -732,31 +1236,31 @@ static void atm_remove(struct solos_card *card)
 static void fpga_remove(struct pci_dev *dev)
 {
 	struct solos_card *card = pci_get_drvdata(dev);
+	
+	/* Disable IRQs */
+	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
-	if (debug)
-		return;
+	/* Reset FPGA */
+	iowrite32(1, card->config_regs + FPGA_MODE);
+	(void)ioread32(card->config_regs + FPGA_MODE); 
 
 	atm_remove(card);
 
-	dev_vdbg(&dev->dev, "Freeing IRQ\n");
-	// Disable IRQs from FPGA
-	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 	free_irq(dev->irq, card);
 	tasklet_kill(&card->tlet);
 
-	//	iowrite32(0x01,pciregs);
-	dev_vdbg(&dev->dev, "Unmapping PCI resource\n");
+	/* Release device from reset */
+	iowrite32(0, card->config_regs + FPGA_MODE);
+	(void)ioread32(card->config_regs + FPGA_MODE); 
+
 	pci_iounmap(dev, card->buffers);
 	pci_iounmap(dev, card->config_regs);
 
-	dev_vdbg(&dev->dev, "Releasing PCI Region\n");
 	pci_release_regions(dev);
 	pci_disable_device(dev);
 
 	pci_set_drvdata(dev, NULL);
 	kfree(card);
-//	dev_dbg(&card->dev->dev, "fpga_remove\n");
-	return;
 }
 
 static struct pci_device_id fpga_pci_tbl[] __devinitdata = {
diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c
new file mode 100644
index 0000000..efa2808
--- /dev/null
+++ b/drivers/atm/solos-attrlist.c
@@ -0,0 +1,70 @@
+SOLOS_ATTR_RO(DriverVersion)
+SOLOS_ATTR_RO(APIVersion)
+SOLOS_ATTR_RO(FirmwareVersion)
+// SOLOS_ATTR_RO(DspVersion)
+// SOLOS_ATTR_RO(CommonHandshake)
+SOLOS_ATTR_RO(Connected)
+SOLOS_ATTR_RO(OperationalMode)
+SOLOS_ATTR_RO(State)
+SOLOS_ATTR_RO(Watchdog)
+SOLOS_ATTR_RO(OperationProgress)
+SOLOS_ATTR_RO(LastFailed)
+SOLOS_ATTR_RO(TxBitRate)
+SOLOS_ATTR_RO(RxBitRate)
+// SOLOS_ATTR_RO(DeltACTATPds)
+// SOLOS_ATTR_RO(DeltACTATPus)
+SOLOS_ATTR_RO(TxATTNDR)
+SOLOS_ATTR_RO(RxATTNDR)
+SOLOS_ATTR_RO(AnnexType)
+SOLOS_ATTR_RO(GeneralFailure)
+SOLOS_ATTR_RO(InterleaveDpDn)
+SOLOS_ATTR_RO(InterleaveDpUp)
+SOLOS_ATTR_RO(RSCorrectedErrorsDn)
+SOLOS_ATTR_RO(RSUnCorrectedErrorsDn)
+SOLOS_ATTR_RO(RSCorrectedErrorsUp)
+SOLOS_ATTR_RO(RSUnCorrectedErrorsUp)
+SOLOS_ATTR_RO(InterleaveRDn)
+SOLOS_ATTR_RO(InterleaveRUp)
+SOLOS_ATTR_RO(ShowtimeStart)
+SOLOS_ATTR_RO(ATURVendor)
+SOLOS_ATTR_RO(ATUCCountry)
+SOLOS_ATTR_RO(ATURANSIRev)
+SOLOS_ATTR_RO(ATURANSISTD)
+SOLOS_ATTR_RO(ATUCANSIRev)
+SOLOS_ATTR_RO(ATUCANSIId)
+SOLOS_ATTR_RO(ATUCANSISTD)
+SOLOS_ATTR_RO(DataBoost)
+SOLOS_ATTR_RO(LocalITUCountryCode)
+SOLOS_ATTR_RO(LocalSEF)
+SOLOS_ATTR_RO(LocalEndLOS)
+SOLOS_ATTR_RO(LocalSNRMargin)
+SOLOS_ATTR_RO(LocalLineAttn)
+SOLOS_ATTR_RO(RawAttn)
+SOLOS_ATTR_RO(LocalTxPower)
+SOLOS_ATTR_RO(RemoteTxPower)
+SOLOS_ATTR_RO(RemoteSEF)
+SOLOS_ATTR_RO(RemoteLOS)
+SOLOS_ATTR_RO(RemoteLineAttn)
+SOLOS_ATTR_RO(RemoteSNRMargin)
+SOLOS_ATTR_RO(LineUpCount)
+SOLOS_ATTR_RO(SRACnt)
+SOLOS_ATTR_RO(SRACntUp)
+SOLOS_ATTR_RO(ProfileStatus)
+SOLOS_ATTR_RW(Action)
+SOLOS_ATTR_RW(ActivateLine)
+SOLOS_ATTR_RO(LineStatus)
+SOLOS_ATTR_RW(HostControl)
+SOLOS_ATTR_RW(AutoStart)
+SOLOS_ATTR_RW(Failsafe)
+SOLOS_ATTR_RW(ShowtimeLed)
+SOLOS_ATTR_RW(Retrain)
+SOLOS_ATTR_RW(Defaults)
+SOLOS_ATTR_RW(LineMode)
+SOLOS_ATTR_RW(Profile)
+SOLOS_ATTR_RW(DetectNoise)
+SOLOS_ATTR_RO(SupportedAnnexes)
+SOLOS_ATTR_RO(Status)
+SOLOS_ATTR_RO(TotalStart)
+SOLOS_ATTR_RO(RecentShowtimeStart)
+SOLOS_ATTR_RO(TotalRxBlocks)
+SOLOS_ATTR_RO(TotalTxBlocks)

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [GIT *] Solos PCI ADSL card update
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
@ 2009-03-17 19:23 ` David Miller
  2009-03-17 20:41   ` Stephen Hemminger
  2009-03-17 21:33   ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 01/30] solos: Fix length header in FPGA transfers David Woodhouse
                   ` (29 subsequent siblings)
  30 siblings, 2 replies; 38+ messages in thread
From: David Miller @ 2009-03-17 19:23 UTC (permalink / raw)
  To: dwmw2; +Cc: netdev, linux-atm-general, chas

From: David Woodhouse <dwmw2@infradead.org>
Date: Tue, 17 Mar 2009 17:19:30 +0000

> Please pull from git://git.infradead.org/~dwmw2/solos-2.6.git
> 
> This contains a bunch of updates to the Solos PCI driver (full patch
> below for review):

So if I don't like patch 3 and want to discuss it as a unit,
what do I do?  Pull the patch out of your GIT repo and
start a thread to discuss it?

Come on, post the whole series, please. :-/

Nobody can review this huge hunk of intertwines changes.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [GIT *] Solos PCI ADSL card update
  2009-03-17 19:23 ` David Miller
@ 2009-03-17 20:41   ` Stephen Hemminger
  2009-03-17 21:36     ` David Woodhouse
  2009-03-17 21:33   ` David Woodhouse
  1 sibling, 1 reply; 38+ messages in thread
From: Stephen Hemminger @ 2009-03-17 20:41 UTC (permalink / raw)
  To: David Miller; +Cc: dwmw2, netdev, linux-atm-general, chas

On Tue, 17 Mar 2009 12:23:17 -0700 (PDT)
David Miller <davem@davemloft.net> wrote:

> From: David Woodhouse <dwmw2@infradead.org>
> Date: Tue, 17 Mar 2009 17:19:30 +0000
> 
> > Please pull from git://git.infradead.org/~dwmw2/solos-2.6.git
> > 
> > This contains a bunch of updates to the Solos PCI driver (full patch
> > below for review):
> 
> So if I don't like patch 3 and want to discuss it as a unit,
> what do I do?  Pull the patch out of your GIT repo and
> start a thread to discuss it?
> 
> Come on, post the whole series, please. :-/
> 
> Nobody can review this huge hunk of intertwines changes.
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

I regret ever adding sysfs for network devices when it gets used
for configuration interfaces like this mess.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 01/30] solos: Fix length header in FPGA transfers
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
  2009-03-17 19:23 ` David Miller
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 02/30] solos: Slight debugging improvements David Woodhouse
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

The length field shouldn't ever include the size of the header itself.
This fixes the problem that some people were seeing with 1500-byte
packets.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 72fc0f7..f030954 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -356,7 +356,7 @@ static int popen(struct atm_vcc *vcc)
 	}
 	header = (void *)skb_put(skb, sizeof(*header));
 
-	header->size = cpu_to_le16(sizeof(*header));
+	header->size = cpu_to_le16(0);
 	header->vpi = cpu_to_le16(vcc->vpi);
 	header->vci = cpu_to_le16(vcc->vci);
 	header->type = cpu_to_le16(PKT_POPEN);
@@ -389,7 +389,7 @@ static void pclose(struct atm_vcc *vcc)
 	}
 	header = (void *)skb_put(skb, sizeof(*header));
 
-	header->size = cpu_to_le16(sizeof(*header));
+	header->size = cpu_to_le16(0);
 	header->vpi = cpu_to_le16(vcc->vpi);
 	header->vci = cpu_to_le16(vcc->vci);
 	header->type = cpu_to_le16(PKT_PCLOSE);
@@ -507,6 +507,7 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 	struct solos_card *card = vcc->dev->dev_data;
 	struct sk_buff *skb2 = NULL;
 	struct pkt_hdr *header;
+	int pktlen;
 
 	//dev_dbg(&card->dev->dev, "psend called.\n");
 	//dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci);
@@ -524,7 +525,8 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 		return 0;
 	}
 
-	if (skb->len > (BUF_SIZE - sizeof(*header))) {
+	pktlen = skb->len;
+	if (pktlen > (BUF_SIZE - sizeof(*header))) {
 		dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n");
 		solos_pop(vcc, skb);
 		return 0;
@@ -546,7 +548,8 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 
 	header = (void *)skb_push(skb, sizeof(*header));
 
-	header->size = cpu_to_le16(skb->len);
+	/* This does _not_ include the size of the header */
+	header->size = cpu_to_le16(pktlen);
 	header->vpi = cpu_to_le16(vcc->vpi);
 	header->vci = cpu_to_le16(vcc->vci);
 	header->type = cpu_to_le16(PKT_DATA);
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 02/30] solos: Slight debugging improvements
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
  2009-03-17 19:23 ` David Miller
  2009-03-17 21:29 ` [PATCH 01/30] solos: Fix length header in FPGA transfers David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 03/30] solos: FPGA and firmware update support David Woodhouse
                   ` (27 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Print a message if pskb_expand_head fails.

Make atmdebug writable by root, so that you can turn printing of data sent to
and received from the card on and off at runtime - useful for tracking
corruption.

Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index f030954..3daa3a3 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -91,7 +91,7 @@ MODULE_LICENSE("GPL");
 MODULE_PARM_DESC(debug, "Enable Loopback");
 MODULE_PARM_DESC(atmdebug, "Print ATM data");
 module_param(debug, int, 0444);
-module_param(atmdebug, int, 0444);
+module_param(atmdebug, int, 0644);
 
 static int opens;
 
@@ -541,6 +541,7 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 
 		ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC);
 		if (ret) {
+			dev_warn(&card->dev->dev, "pskb_expand_head failed.\n");
 			solos_pop(vcc, skb);
 			return ret;
 		}
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 03/30] solos: FPGA and firmware update support.
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (2 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 02/30] solos: Slight debugging improvements David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 04/30] solos: Clean up firmware loading code David Woodhouse
                   ` (26 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

This is just a straight pull in of changes, syncing us up to 0.07 from
openadsl.sf.net

Signed-off-by: Nathan Williams <nathan@traverse.com.au>
Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |  171 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 3daa3a3..2b472c8 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -9,6 +9,7 @@
  *
  * Authors: Nathan Williams <nathan@traverse.com.au>
  *          David Woodhouse <dwmw2@infradead.org>
+ *          Treker Chen <treker@xrio.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -36,8 +37,9 @@
 #include <linux/sysfs.h>
 #include <linux/device.h>
 #include <linux/kobject.h>
+#include <linux/firmware.h>
 
-#define VERSION "0.04"
+#define VERSION "0.07"
 #define PTAG "solos-pci"
 
 #define CONFIG_RAM_SIZE	128
@@ -45,16 +47,27 @@
 #define IRQ_EN_ADDR	0x78
 #define FPGA_VER	0x74
 #define IRQ_CLEAR	0x70
-#define BUG_FLAG	0x6C
+#define WRITE_FLASH	0x6C
+#define PORTS		0x68
+#define FLASH_BLOCK	0x64
+#define FLASH_BUSY	0x60
+#define FPGA_MODE	0x5C
+#define FLASH_MODE	0x58
 
 #define DATA_RAM_SIZE	32768
 #define BUF_SIZE	4096
+#define FPGA_PAGE	528 /* FPGA flash page size*/
+#define SOLOS_PAGE	512 /* Solos flash page size*/
+#define FPGA_BLOCK	(FPGA_PAGE * 8) /* FPGA flash block size*/
+#define SOLOS_BLOCK	(SOLOS_PAGE * 8) /* Solos flash block size*/
 
 #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
 #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)
 
 static int debug = 0;
 static int atmdebug = 0;
+static int firmware_upgrade = 0;
+static int fpga_upgrade = 0;
 
 struct pkt_hdr {
 	__le16 size;
@@ -80,6 +93,7 @@ struct solos_card {
 	spinlock_t cli_queue_lock;
 	struct sk_buff_head tx_queue[4];
 	struct sk_buff_head cli_queue[4];
+	int flash_chip;
 };
 
 #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
@@ -90,11 +104,19 @@ MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_PARM_DESC(debug, "Enable Loopback");
 MODULE_PARM_DESC(atmdebug, "Print ATM data");
+MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
+MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
 module_param(debug, int, 0444);
 module_param(atmdebug, int, 0644);
+module_param(firmware_upgrade, int, 0444);
+module_param(fpga_upgrade, int, 0444);
 
 static int opens;
+static struct firmware *fw;
+static int flash_offset;
 
+void flash_upgrade(struct solos_card *);
+void flash_write(struct solos_card *);
 static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc);
 static int fpga_tx(struct solos_card *);
@@ -180,6 +202,131 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(console, 0644, console_show, console_store);
 
+void flash_upgrade(struct solos_card *card){
+	uint32_t data32 = 0;
+	int blocksize = 0;
+	int numblocks = 0;
+	dev_info(&card->dev->dev, "Flash upgrade started\n");
+	if (card->flash_chip == 0) {
+		if (request_firmware((const struct firmware **)&fw,
+				"solos-FPGA.bin",&card->dev->dev))
+		{
+			dev_info(&card->dev->dev,
+					"Failed to find firmware\n");
+			return;
+		}
+		blocksize = FPGA_BLOCK;
+	} else {
+		if (request_firmware((const struct firmware **)&fw,
+				"solos-Firmware.bin",&card->dev->dev))
+		{
+			dev_info(&card->dev->dev,
+					"Failed to find firmware\n");
+			return;
+		}
+		blocksize = SOLOS_BLOCK;
+	}
+	numblocks = fw->size/blocksize;
+	dev_info(&card->dev->dev, "Firmware size: %d\n", fw->size);
+	dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
+	
+		
+	dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
+	iowrite32(1, card->config_regs + FPGA_MODE);
+	data32 = ioread32(card->config_regs + FPGA_MODE); 
+	/*Set mode to Chip Erase*/
+	if (card->flash_chip == 0) {
+		dev_info(&card->dev->dev, 
+				"Set FPGA Flash mode to FPGA Chip Erase\n");
+	} else {
+		dev_info(&card->dev->dev, 
+				"Set FPGA Flash mode to Solos Chip Erase\n");
+	}
+	iowrite32((card->flash_chip * 2), card->config_regs + FLASH_MODE);
+	flash_offset = 0;
+	iowrite32(1, card->config_regs + WRITE_FLASH);
+	return;
+}
+
+void flash_write(struct solos_card *card){
+	int block;
+	int block_num;
+	int blocksize;
+	int i;
+	uint32_t data32 = 0;
+
+	/*Clear write flag*/
+	iowrite32(0, card->config_regs + WRITE_FLASH);
+	/*Set mode to Block Write*/
+	/*dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n");*/
+	iowrite32(((card->flash_chip * 2) + 1), card->config_regs + FLASH_MODE);
+
+	/*When finished programming flash, release firmware and exit*/
+	if (fw->size - flash_offset == 0) {
+		//release_firmware(fw); /* This crashes for some reason */
+		iowrite32(0, card->config_regs + WRITE_FLASH);
+		iowrite32(0, card->config_regs + FPGA_MODE);
+		iowrite32(0, card->config_regs + FLASH_MODE);
+		dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
+		return;
+	}
+	if (card->flash_chip == 0) {
+		blocksize = FPGA_BLOCK;
+	} else {
+		blocksize = SOLOS_BLOCK;
+	}
+	
+	/*Calculate block size*/
+	if ((fw->size - flash_offset) > blocksize) {
+		block = blocksize;
+	} else {
+		block = fw->size - flash_offset;
+	}
+	block_num = flash_offset / blocksize;
+	//dev_info(&card->dev->dev, "block %d/%d\n",block_num + 1,(fw->size/512/8));
+
+	/*Copy block into RAM*/
+	for(i=0;i<block;i++){
+		if(i%4 == 0){
+			//dev_info(&card->dev->dev, "i: %d\n", i);
+			data32=0x00000000;
+		}
+		
+		switch(i%4){
+		case 0:
+			data32 |= 0x0000FF00 & 
+				(*(fw->data + i + flash_offset)	<< 8);
+			break;
+		case 1:
+			data32 |= 0x000000FF & *(fw->data + i + flash_offset);
+			break;
+		case 2:
+			data32 |= 0xFF000000 &
+					(*(fw->data + i + flash_offset)	<< 24);
+			break;
+		case 3:
+			data32 |= 0x00FF0000 &
+					(*(fw->data + i + flash_offset)	<< 16);
+			break;
+		}
+
+		if (i%4 == 3) {
+			iowrite32(data32, RX_BUF(card, 3) + i - 3);
+		}
+	}
+	i--;
+	if (i%4 != 3) {
+		iowrite32(data32, RX_BUF(card, 3) + i - (i%4));
+	}
+
+	/*Specify block number and then trigger flash write*/
+	iowrite32(block_num, card->config_regs + FLASH_BLOCK);
+	iowrite32(1, card->config_regs + WRITE_FLASH);
+//	iowrite32(0, card->config_regs + WRITE_FLASH);
+	flash_offset += block;
+	return;
+}
+
 static irqreturn_t solos_irq(int irq, void *dev_id)
 {
 	struct solos_card *card = dev_id;
@@ -207,6 +354,17 @@ void solos_bh(unsigned long card_arg)
 	uint32_t card_flags;
 	uint32_t tx_mask;
 	uint32_t rx_done = 0;
+	uint32_t data32;
+
+	data32 = ioread32(card->config_regs + FPGA_MODE); 
+	if (data32 != 0) {
+		data32 = ioread32(card->config_regs + FLASH_BUSY); 
+		if (data32 == 0) {
+			flash_write(card);
+		}	
+		return;
+	}
+		
 
 	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
 
@@ -680,6 +838,15 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	// Enable IRQs
 	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 
+	if(firmware_upgrade != 0){
+		card->flash_chip = 1;
+		flash_upgrade(card);
+	} else {
+		if(fpga_upgrade != 0){
+			card->flash_chip = 0;
+			flash_upgrade(card);
+		}
+	}
 	return 0;
 
  out_unmap_both:
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 04/30] solos: Clean up firmware loading code
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (3 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 03/30] solos: FPGA and firmware update support David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 05/30] solos: Kill global 'opens' count David Woodhouse
                   ` (25 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

We no longer try to load firmware while the ATM is up and running.
However, this means that we _do_ make init_module() wait for it, and it
takes a long time for now (since we're using ultra-conservative code in
the FPGA for that too).

The inner loop which uses swahb32p() was by Simon Farnsworth.

Simon has patches which migrate us to request_firmware_nowait(), for
which we'll actually need to take down the ATM devices, do the upgrade,
then reregister them.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |  209 ++++++++++++++++------------------------------
 1 files changed, 73 insertions(+), 136 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 2b472c8..89bdf73 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -93,7 +93,7 @@ struct solos_card {
 	spinlock_t cli_queue_lock;
 	struct sk_buff_head tx_queue[4];
 	struct sk_buff_head cli_queue[4];
-	int flash_chip;
+	wait_queue_head_t fw_wq;
 };
 
 #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
@@ -112,11 +112,7 @@ module_param(firmware_upgrade, int, 0444);
 module_param(fpga_upgrade, int, 0444);
 
 static int opens;
-static struct firmware *fw;
-static int flash_offset;
 
-void flash_upgrade(struct solos_card *);
-void flash_write(struct solos_card *);
 static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc);
 static int fpga_tx(struct solos_card *);
@@ -202,129 +198,73 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(console, 0644, console_show, console_store);
 
-void flash_upgrade(struct solos_card *card){
+static int flash_upgrade(struct solos_card *card, int chip)
+{
+	const struct firmware *fw;
+	const char *fw_name;
 	uint32_t data32 = 0;
 	int blocksize = 0;
 	int numblocks = 0;
-	dev_info(&card->dev->dev, "Flash upgrade started\n");
-	if (card->flash_chip == 0) {
-		if (request_firmware((const struct firmware **)&fw,
-				"solos-FPGA.bin",&card->dev->dev))
-		{
-			dev_info(&card->dev->dev,
-					"Failed to find firmware\n");
-			return;
-		}
+	int offset;
+
+	if (chip == 0) {
+		fw_name = "solos-FPGA.bin";
 		blocksize = FPGA_BLOCK;
 	} else {
-		if (request_firmware((const struct firmware **)&fw,
-				"solos-Firmware.bin",&card->dev->dev))
-		{
-			dev_info(&card->dev->dev,
-					"Failed to find firmware\n");
-			return;
-		}
+		fw_name = "solos-Firmware.bin";
 		blocksize = SOLOS_BLOCK;
 	}
-	numblocks = fw->size/blocksize;
-	dev_info(&card->dev->dev, "Firmware size: %d\n", fw->size);
+
+	if (request_firmware(&fw, fw_name, &card->dev->dev))
+		return -ENOENT;
+
+	dev_info(&card->dev->dev, "Flash upgrade starting\n");
+
+	numblocks = fw->size / blocksize;
+	dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size);
 	dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
 	
-		
 	dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
 	iowrite32(1, card->config_regs + FPGA_MODE);
 	data32 = ioread32(card->config_regs + FPGA_MODE); 
-	/*Set mode to Chip Erase*/
-	if (card->flash_chip == 0) {
-		dev_info(&card->dev->dev, 
-				"Set FPGA Flash mode to FPGA Chip Erase\n");
-	} else {
-		dev_info(&card->dev->dev, 
-				"Set FPGA Flash mode to Solos Chip Erase\n");
-	}
-	iowrite32((card->flash_chip * 2), card->config_regs + FLASH_MODE);
-	flash_offset = 0;
-	iowrite32(1, card->config_regs + WRITE_FLASH);
-	return;
-}
 
-void flash_write(struct solos_card *card){
-	int block;
-	int block_num;
-	int blocksize;
-	int i;
-	uint32_t data32 = 0;
+	/* Set mode to Chip Erase */
+	dev_info(&card->dev->dev, "Set FPGA Flash mode to %s Chip Erase\n",
+		 chip?"Solos":"FPGA");
+	iowrite32((chip * 2), card->config_regs + FLASH_MODE);
 
-	/*Clear write flag*/
-	iowrite32(0, card->config_regs + WRITE_FLASH);
-	/*Set mode to Block Write*/
-	/*dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n");*/
-	iowrite32(((card->flash_chip * 2) + 1), card->config_regs + FLASH_MODE);
 
-	/*When finished programming flash, release firmware and exit*/
-	if (fw->size - flash_offset == 0) {
-		//release_firmware(fw); /* This crashes for some reason */
+	iowrite32(1, card->config_regs + WRITE_FLASH);
+	wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
+
+	for (offset = 0; offset < fw->size; offset += blocksize) {
+		int i;
+
+		/* Clear write flag */
 		iowrite32(0, card->config_regs + WRITE_FLASH);
-		iowrite32(0, card->config_regs + FPGA_MODE);
-		iowrite32(0, card->config_regs + FLASH_MODE);
-		dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
-		return;
-	}
-	if (card->flash_chip == 0) {
-		blocksize = FPGA_BLOCK;
-	} else {
-		blocksize = SOLOS_BLOCK;
-	}
-	
-	/*Calculate block size*/
-	if ((fw->size - flash_offset) > blocksize) {
-		block = blocksize;
-	} else {
-		block = fw->size - flash_offset;
-	}
-	block_num = flash_offset / blocksize;
-	//dev_info(&card->dev->dev, "block %d/%d\n",block_num + 1,(fw->size/512/8));
-
-	/*Copy block into RAM*/
-	for(i=0;i<block;i++){
-		if(i%4 == 0){
-			//dev_info(&card->dev->dev, "i: %d\n", i);
-			data32=0x00000000;
-		}
-		
-		switch(i%4){
-		case 0:
-			data32 |= 0x0000FF00 & 
-				(*(fw->data + i + flash_offset)	<< 8);
-			break;
-		case 1:
-			data32 |= 0x000000FF & *(fw->data + i + flash_offset);
-			break;
-		case 2:
-			data32 |= 0xFF000000 &
-					(*(fw->data + i + flash_offset)	<< 24);
-			break;
-		case 3:
-			data32 |= 0x00FF0000 &
-					(*(fw->data + i + flash_offset)	<< 16);
-			break;
-		}
 
-		if (i%4 == 3) {
-			iowrite32(data32, RX_BUF(card, 3) + i - 3);
+		/* Set mode to Block Write */
+		/* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */
+		iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE);
+
+		/* Copy block to buffer, swapping each 16 bits */
+		for(i = 0; i < blocksize; i += 4) {
+			uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i));
+			iowrite32(word, RX_BUF(card, 3) + i);
 		}
-	}
-	i--;
-	if (i%4 != 3) {
-		iowrite32(data32, RX_BUF(card, 3) + i - (i%4));
+
+		/* Specify block number and then trigger flash write */
+		iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK);
+		iowrite32(1, card->config_regs + WRITE_FLASH);
+		wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
 	}
 
-	/*Specify block number and then trigger flash write*/
-	iowrite32(block_num, card->config_regs + FLASH_BLOCK);
-	iowrite32(1, card->config_regs + WRITE_FLASH);
-//	iowrite32(0, card->config_regs + WRITE_FLASH);
-	flash_offset += block;
-	return;
+	release_firmware(fw);
+	iowrite32(0, card->config_regs + WRITE_FLASH);
+	iowrite32(0, card->config_regs + FPGA_MODE);
+	iowrite32(0, card->config_regs + FLASH_MODE);
+	dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
+	return 0;
 }
 
 static irqreturn_t solos_irq(int irq, void *dev_id)
@@ -337,10 +277,10 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
 	//Disable IRQs from FPGA
 	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
-	/* If we only do it when the device is open, we lose console
-	   messages */
-	if (1 || opens)
+	if (card->atmdev[0])
 		tasklet_schedule(&card->tlet);
+	else
+		wake_up(&card->fw_wq);
 
 	//Enable IRQs from FPGA
 	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
@@ -354,17 +294,6 @@ void solos_bh(unsigned long card_arg)
 	uint32_t card_flags;
 	uint32_t tx_mask;
 	uint32_t rx_done = 0;
-	uint32_t data32;
-
-	data32 = ioread32(card->config_regs + FPGA_MODE); 
-	if (data32 != 0) {
-		data32 = ioread32(card->config_regs + FLASH_BUSY); 
-		if (data32 == 0) {
-			flash_write(card);
-		}	
-		return;
-	}
-		
 
 	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
 
@@ -749,6 +678,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		return -ENOMEM;
 
 	card->dev = dev;
+	init_waitqueue_head(&card->fw_wq);
 
 	err = pci_enable_device(dev);
 	if (err) {
@@ -794,15 +724,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	card->nr_ports = 2; /* FIXME: Detect daughterboard */
 
-	err = atm_init(card);
-	if (err)
-		goto out_unmap_both;
-
 	pci_set_drvdata(dev, card);
+
 	tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
 	spin_lock_init(&card->tx_lock);
 	spin_lock_init(&card->tx_queue_lock);
 	spin_lock_init(&card->cli_queue_lock);
+
 /*
 	// Set Loopback mode
 	data32 = 0x00010000;
@@ -832,24 +760,33 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	//dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq);
 	err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED,
 			  "solos-pci", card);
-	if (err)
+	if (err) {
 		dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq);
+		goto out_unmap_both;
+	}
 
 	// Enable IRQs
 	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 
-	if(firmware_upgrade != 0){
-		card->flash_chip = 1;
-		flash_upgrade(card);
-	} else {
-		if(fpga_upgrade != 0){
-			card->flash_chip = 0;
-			flash_upgrade(card);
-		}
-	}
+	if (fpga_upgrade)
+		flash_upgrade(card, 0);
+
+	if (firmware_upgrade)
+		flash_upgrade(card, 1);
+
+	err = atm_init(card);
+	if (err)
+		goto out_free_irq;
+
 	return 0;
 
+ out_free_irq:
+	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+	free_irq(dev->irq, card);
+	tasklet_kill(&card->tlet);
+	
  out_unmap_both:
+	pci_set_drvdata(dev, NULL);
 	pci_iounmap(dev, card->config_regs);
  out_unmap_config:
 	pci_iounmap(dev, card->buffers);
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 05/30] solos: Kill global 'opens' count.
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (4 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 04/30] solos: Clean up firmware loading code David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely David Woodhouse
                   ` (24 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   10 ----------
 1 files changed, 0 insertions(+), 10 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 89bdf73..5179dbf 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -111,8 +111,6 @@ module_param(atmdebug, int, 0644);
 module_param(firmware_upgrade, int, 0444);
 module_param(fpga_upgrade, int, 0444);
 
-static int opens;
-
 static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc);
 static int fpga_tx(struct solos_card *);
@@ -455,10 +453,6 @@ static int popen(struct atm_vcc *vcc)
 	set_bit(ATM_VF_READY, &vcc->flags);
 	list_vccs(0);
 
-	if (!opens)
-		iowrite32(1, card->config_regs + IRQ_EN_ADDR);
-
-	opens++; //count open PVCs
 
 	return 0;
 }
@@ -484,8 +478,6 @@ static void pclose(struct atm_vcc *vcc)
 	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
 //	dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-	if (!--opens)
-		iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
 	clear_bit(ATM_VF_ADDR, &vcc->flags);
 	clear_bit(ATM_VF_READY, &vcc->flags);
@@ -800,8 +792,6 @@ static int atm_init(struct solos_card *card)
 {
 	int i;
 
-	opens = 0;
-
 	for (i = 0; i < card->nr_ports; i++) {
 		skb_queue_head_init(&card->tx_queue[i]);
 		skb_queue_head_init(&card->cli_queue[i]);
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (5 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 05/30] solos: Kill global 'opens' count David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 22:44   ` Stephen Hemminger
  2009-03-17 21:29 ` [PATCH 08/30] solos: Handle new line status change packets, hook up to ATM layer info David Woodhouse
                   ` (23 subsequent siblings)
  30 siblings, 1 reply; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

There are still a _lot_ of attributes, but for at least the basic ones
we want to be able to get/set them from the kernel. Especially the ones
we want to inform the ATM core about (link state, speed).

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |  187 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 187 insertions(+), 0 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 5179dbf..d9262a4 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -38,6 +38,8 @@
 #include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/firmware.h>
+#include <linux/ctype.h>
+#include <linux/swab.h>
 
 #define VERSION "0.07"
 #define PTAG "solos-pci"
@@ -91,11 +93,23 @@ struct solos_card {
 	spinlock_t tx_lock;
 	spinlock_t tx_queue_lock;
 	spinlock_t cli_queue_lock;
+	spinlock_t param_queue_lock;
+	struct list_head param_queue;
 	struct sk_buff_head tx_queue[4];
 	struct sk_buff_head cli_queue[4];
+	wait_queue_head_t param_wq;
 	wait_queue_head_t fw_wq;
 };
 
+
+struct solos_param {
+	struct list_head list;
+	pid_t pid;
+	int port;
+	struct sk_buff *response;
+	wait_queue_head_t wq;
+};
+
 #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
 
 MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
@@ -131,6 +145,168 @@ static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb)
                 dev_kfree_skb_any(skb);
 }
 
+static ssize_t solos_param_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+	struct solos_card *card = atmdev->dev_data;
+	struct solos_param prm;
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+	int buflen;
+
+	buflen = strlen(attr->attr.name) + 10;
+
+	skb = alloc_skb(buflen, GFP_KERNEL);
+	if (!skb) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n");
+		return -ENOMEM;
+	}
+
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	buflen = snprintf((void *)&header[1], buflen - 1,
+			  "L%05d\n%s\n", current->pid, attr->attr.name);
+	skb_put(skb, buflen);
+
+	header->size = cpu_to_le16(buflen);
+	header->vpi = cpu_to_le16(0);
+	header->vci = cpu_to_le16(0);
+	header->type = cpu_to_le16(PKT_COMMAND);
+
+	prm.pid = current->pid;
+	prm.response = NULL;
+	prm.port = SOLOS_CHAN(atmdev);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_add(&prm.list, &card->param_queue);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	fpga_queue(card, prm.port, skb, NULL);
+
+	wait_event_timeout(card->param_wq, prm.response, 5 * HZ);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_del(&prm.list);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	if (!prm.response)
+		return -EIO;
+
+	buflen = prm.response->len;
+	memcpy(buf, prm.response->data, buflen);
+	kfree_skb(prm.response);
+
+	return buflen;
+}
+
+static ssize_t solos_param_store(struct device *dev, struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+	struct solos_card *card = atmdev->dev_data;
+	struct solos_param prm;
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+	int buflen;
+	ssize_t ret;
+
+	buflen = strlen(attr->attr.name) + 11 + count;
+
+	skb = alloc_skb(buflen, GFP_KERNEL);
+	if (!skb) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n");
+		return -ENOMEM;
+	}
+
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	buflen = snprintf((void *)&header[1], buflen - 1,
+			  "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf);
+
+	skb_put(skb, buflen);
+	header->size = cpu_to_le16(buflen);
+	header->vpi = cpu_to_le16(0);
+	header->vci = cpu_to_le16(0);
+	header->type = cpu_to_le16(PKT_COMMAND);
+
+	prm.pid = current->pid;
+	prm.response = NULL;
+	prm.port = SOLOS_CHAN(atmdev);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_add(&prm.list, &card->param_queue);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	fpga_queue(card, prm.port, skb, NULL);
+
+	wait_event_timeout(card->param_wq, prm.response, 5 * HZ);
+
+	spin_lock_irq(&card->param_queue_lock);
+	list_del(&prm.list);
+	spin_unlock_irq(&card->param_queue_lock);
+
+	skb = prm.response;
+
+	if (!skb)
+		return -EIO;
+
+	buflen = skb->len;
+
+	/* Sometimes it has a newline, sometimes it doesn't. */
+	if (skb->data[buflen - 1] == '\n')
+		buflen--;
+
+	if (buflen == 2 && !strncmp(skb->data, "OK", 2))
+		ret = count;
+	else if (buflen == 5 && !strncmp(skb->data, "ERROR", 5))
+		ret = -EIO;
+	else {
+		/* We know we have enough space allocated for this; we allocated 
+		   it ourselves */
+		skb->data[buflen] = 0;
+	
+		dev_warn(&card->dev->dev, "Unexpected parameter response: '%s'\n",
+			 skb->data);
+		ret = -EIO;
+	}
+	kfree_skb(skb);
+
+	return ret;
+}
+
+static int process_command(struct solos_card *card, int port, struct sk_buff *skb)
+{
+	struct solos_param *prm;
+	unsigned long flags;
+	int cmdpid;
+	int found = 0;
+
+	if (skb->len < 7)
+		return 0;
+
+	if (skb->data[0] != 'L'    || !isdigit(skb->data[1]) ||
+	    !isdigit(skb->data[2]) || !isdigit(skb->data[3]) ||
+	    !isdigit(skb->data[4]) || !isdigit(skb->data[5]) ||
+	    skb->data[6] != '\n')
+		return 0;
+
+	cmdpid = simple_strtol(&skb->data[1], NULL, 10);
+
+	spin_lock_irqsave(&card->param_queue_lock, flags);
+	list_for_each_entry(prm, &card->param_queue, list) {
+		if (prm->port == port && prm->pid == cmdpid) {
+			prm->response = skb;
+			skb_pull(skb, 7);
+			wake_up(&card->param_wq);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&card->param_queue_lock, flags);
+	return found;
+}
+
 static ssize_t console_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
@@ -195,6 +371,8 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
 }
 
 static DEVICE_ATTR(console, 0644, console_show, console_store);
+static DEVICE_ATTR(OperationalMode, 0444, solos_param_show, NULL);
+static DEVICE_ATTR(AutoStart, 0644, solos_param_show, solos_param_store);
 
 static int flash_upgrade(struct solos_card *card, int chip)
 {
@@ -351,6 +529,8 @@ void solos_bh(unsigned long card_arg)
 
 			case PKT_COMMAND:
 			default: /* FIXME: Not really, surely? */
+				if (process_command(card, port, skb))
+					break;
 				spin_lock(&card->cli_queue_lock);
 				if (skb_queue_len(&card->cli_queue[port]) > 10) {
 					if (net_ratelimit())
@@ -671,6 +851,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	card->dev = dev;
 	init_waitqueue_head(&card->fw_wq);
+	init_waitqueue_head(&card->param_wq);
 
 	err = pci_enable_device(dev);
 	if (err) {
@@ -722,6 +903,8 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	spin_lock_init(&card->tx_lock);
 	spin_lock_init(&card->tx_queue_lock);
 	spin_lock_init(&card->cli_queue_lock);
+	spin_lock_init(&card->param_queue_lock);
+	INIT_LIST_HEAD(&card->param_queue);
 
 /*
 	// Set Loopback mode
@@ -804,6 +987,10 @@ static int atm_init(struct solos_card *card)
 		}
 		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console))
 			dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i);
+		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_OperationalMode))
+			dev_err(&card->dev->dev, "Could not register opmode attr for ATM device %d\n", i);
+		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_AutoStart))
+			dev_err(&card->dev->dev, "Could not register autostart attr for ATM device %d\n", i);
 
 		dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number);
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 07/30] solos: Add initial list of parameters
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (7 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 08/30] solos: Handle new line status change packets, hook up to ATM layer info David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 09/30] solos: Kill existing connections on link down event David Woodhouse
                   ` (21 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

I don't much like the trick with multiple inclusions of solos-attrlist.c
but don't really see a saner way to do it without repeating the list.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-attrlist.c |   70 ++++++++++++++++++++++++++++++++++++++++++
 drivers/atm/solos-pci.c      |   30 ++++++++++++++---
 2 files changed, 94 insertions(+), 6 deletions(-)
 create mode 100644 drivers/atm/solos-attrlist.c

diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c
new file mode 100644
index 0000000..efa2808
--- /dev/null
+++ b/drivers/atm/solos-attrlist.c
@@ -0,0 +1,70 @@
+SOLOS_ATTR_RO(DriverVersion)
+SOLOS_ATTR_RO(APIVersion)
+SOLOS_ATTR_RO(FirmwareVersion)
+// SOLOS_ATTR_RO(DspVersion)
+// SOLOS_ATTR_RO(CommonHandshake)
+SOLOS_ATTR_RO(Connected)
+SOLOS_ATTR_RO(OperationalMode)
+SOLOS_ATTR_RO(State)
+SOLOS_ATTR_RO(Watchdog)
+SOLOS_ATTR_RO(OperationProgress)
+SOLOS_ATTR_RO(LastFailed)
+SOLOS_ATTR_RO(TxBitRate)
+SOLOS_ATTR_RO(RxBitRate)
+// SOLOS_ATTR_RO(DeltACTATPds)
+// SOLOS_ATTR_RO(DeltACTATPus)
+SOLOS_ATTR_RO(TxATTNDR)
+SOLOS_ATTR_RO(RxATTNDR)
+SOLOS_ATTR_RO(AnnexType)
+SOLOS_ATTR_RO(GeneralFailure)
+SOLOS_ATTR_RO(InterleaveDpDn)
+SOLOS_ATTR_RO(InterleaveDpUp)
+SOLOS_ATTR_RO(RSCorrectedErrorsDn)
+SOLOS_ATTR_RO(RSUnCorrectedErrorsDn)
+SOLOS_ATTR_RO(RSCorrectedErrorsUp)
+SOLOS_ATTR_RO(RSUnCorrectedErrorsUp)
+SOLOS_ATTR_RO(InterleaveRDn)
+SOLOS_ATTR_RO(InterleaveRUp)
+SOLOS_ATTR_RO(ShowtimeStart)
+SOLOS_ATTR_RO(ATURVendor)
+SOLOS_ATTR_RO(ATUCCountry)
+SOLOS_ATTR_RO(ATURANSIRev)
+SOLOS_ATTR_RO(ATURANSISTD)
+SOLOS_ATTR_RO(ATUCANSIRev)
+SOLOS_ATTR_RO(ATUCANSIId)
+SOLOS_ATTR_RO(ATUCANSISTD)
+SOLOS_ATTR_RO(DataBoost)
+SOLOS_ATTR_RO(LocalITUCountryCode)
+SOLOS_ATTR_RO(LocalSEF)
+SOLOS_ATTR_RO(LocalEndLOS)
+SOLOS_ATTR_RO(LocalSNRMargin)
+SOLOS_ATTR_RO(LocalLineAttn)
+SOLOS_ATTR_RO(RawAttn)
+SOLOS_ATTR_RO(LocalTxPower)
+SOLOS_ATTR_RO(RemoteTxPower)
+SOLOS_ATTR_RO(RemoteSEF)
+SOLOS_ATTR_RO(RemoteLOS)
+SOLOS_ATTR_RO(RemoteLineAttn)
+SOLOS_ATTR_RO(RemoteSNRMargin)
+SOLOS_ATTR_RO(LineUpCount)
+SOLOS_ATTR_RO(SRACnt)
+SOLOS_ATTR_RO(SRACntUp)
+SOLOS_ATTR_RO(ProfileStatus)
+SOLOS_ATTR_RW(Action)
+SOLOS_ATTR_RW(ActivateLine)
+SOLOS_ATTR_RO(LineStatus)
+SOLOS_ATTR_RW(HostControl)
+SOLOS_ATTR_RW(AutoStart)
+SOLOS_ATTR_RW(Failsafe)
+SOLOS_ATTR_RW(ShowtimeLed)
+SOLOS_ATTR_RW(Retrain)
+SOLOS_ATTR_RW(Defaults)
+SOLOS_ATTR_RW(LineMode)
+SOLOS_ATTR_RW(Profile)
+SOLOS_ATTR_RW(DetectNoise)
+SOLOS_ATTR_RO(SupportedAnnexes)
+SOLOS_ATTR_RO(Status)
+SOLOS_ATTR_RO(TotalStart)
+SOLOS_ATTR_RO(RecentShowtimeStart)
+SOLOS_ATTR_RO(TotalRxBlocks)
+SOLOS_ATTR_RO(TotalTxBlocks)
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index d9262a4..b0c4676 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -371,8 +371,28 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
 }
 
 static DEVICE_ATTR(console, 0644, console_show, console_store);
-static DEVICE_ATTR(OperationalMode, 0444, solos_param_show, NULL);
-static DEVICE_ATTR(AutoStart, 0644, solos_param_show, solos_param_store);
+
+
+#define SOLOS_ATTR_RO(x) static DEVICE_ATTR(x, 0444, solos_param_show, NULL);
+#define SOLOS_ATTR_RW(x) static DEVICE_ATTR(x, 0644, solos_param_show, solos_param_store);
+
+#include "solos-attrlist.c"
+
+#undef SOLOS_ATTR_RO
+#undef SOLOS_ATTR_RW
+
+#define SOLOS_ATTR_RO(x) &dev_attr_##x.attr,
+#define SOLOS_ATTR_RW(x) &dev_attr_##x.attr,
+
+static struct attribute *solos_attrs[] = {
+#include "solos-attrlist.c"
+	NULL
+};
+
+static struct attribute_group solos_attr_group = {
+	.attrs = solos_attrs,
+	.name = "parameters",
+};
 
 static int flash_upgrade(struct solos_card *card, int chip)
 {
@@ -987,10 +1007,8 @@ static int atm_init(struct solos_card *card)
 		}
 		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console))
 			dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i);
-		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_OperationalMode))
-			dev_err(&card->dev->dev, "Could not register opmode attr for ATM device %d\n", i);
-		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_AutoStart))
-			dev_err(&card->dev->dev, "Could not register autostart attr for ATM device %d\n", i);
+		if (sysfs_create_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group))
+			dev_err(&card->dev->dev, "Could not register parameter group for ATM device %d\n", i);
 
 		dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number);
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 08/30] solos: Handle new line status change packets, hook up to ATM layer info
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (6 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 07/30] solos: Add initial list of parameters David Woodhouse
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   93 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index b0c4676..4c87dfb 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -82,6 +82,7 @@ struct pkt_hdr {
 #define PKT_COMMAND	1
 #define PKT_POPEN	3
 #define PKT_PCLOSE	4
+#define PKT_STATUS	5
 
 struct solos_card {
 	void __iomem *config_regs;
@@ -275,6 +276,72 @@ static ssize_t solos_param_store(struct device *dev, struct device_attribute *at
 	return ret;
 }
 
+static char *next_string(struct sk_buff *skb)
+{
+	int i = 0;
+	char *this = skb->data;
+
+	while (i < skb->len) {
+		if (this[i] == '\n') {
+			this[i] = 0;
+			skb_pull(skb, i);
+			return this;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Status packet has fields separated by \n, starting with a version number
+ * for the information therein. Fields are....
+ *
+ *     packet version
+ *     TxBitRate	(version >= 1)
+ *     RxBitRate	(version >= 1)
+ *     State		(version >= 1)
+ */       
+static int process_status(struct solos_card *card, int port, struct sk_buff *skb)
+{
+	char *str, *end;
+	int ver, rate_up, rate_down, state;
+
+	if (!card->atmdev[port])
+		return -ENODEV;
+
+	str = next_string(skb);
+	if (!str)
+		return -EIO;
+
+	ver = simple_strtol(str, NULL, 10);
+	if (ver < 1) {
+		dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n",
+			 ver);
+		return -EIO;
+	}
+
+	str = next_string(skb);
+	rate_up = simple_strtol(str, &end, 10);
+	if (*end)
+		return -EIO;
+
+	str = next_string(skb);
+	rate_down = simple_strtol(str, &end, 10);
+	if (*end)
+		return -EIO;
+
+	str = next_string(skb);
+	if (!strcmp(str, "Showtime"))
+		state = ATM_PHY_SIG_FOUND;
+	else state = ATM_PHY_SIG_LOST;
+
+	card->atmdev[port]->link_rate = rate_down;
+	card->atmdev[port]->signal = state;
+
+	dev_info(&card->dev->dev, "ATM state: '%s', %d/%d kb/s up/down.\n",
+		 str, rate_up/1000, rate_down/1000);
+	return 0;
+}
+
 static int process_command(struct solos_card *card, int port, struct sk_buff *skb)
 {
 	struct solos_param *prm;
@@ -512,7 +579,7 @@ void solos_bh(unsigned long card_arg)
 
 			size = le16_to_cpu(header.size);
 
-			skb = alloc_skb(size, GFP_ATOMIC);
+			skb = alloc_skb(size + 1, GFP_ATOMIC);
 			if (!skb) {
 				if (net_ratelimit())
 					dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
@@ -547,6 +614,11 @@ void solos_bh(unsigned long card_arg)
 				atomic_inc(&vcc->stats->rx);
 				break;
 
+			case PKT_STATUS:
+				process_status(card, port, skb);
+				dev_kfree_skb(skb);
+				break;
+
 			case PKT_COMMAND:
 			default: /* FIXME: Not really, surely? */
 				if (process_command(card, port, skb))
@@ -996,6 +1068,9 @@ static int atm_init(struct solos_card *card)
 	int i;
 
 	for (i = 0; i < card->nr_ports; i++) {
+		struct sk_buff *skb;
+		struct pkt_hdr *header;
+
 		skb_queue_head_init(&card->tx_queue[i]);
 		skb_queue_head_init(&card->cli_queue[i]);
 
@@ -1016,6 +1091,22 @@ static int atm_init(struct solos_card *card)
 		card->atmdev[i]->ci_range.vci_bits = 16;
 		card->atmdev[i]->dev_data = card;
 		card->atmdev[i]->phy_data = (void *)(unsigned long)i;
+		card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN;
+
+		skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
+		if (!skb) {
+			dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n");
+			continue;
+		}
+
+		header = (void *)skb_put(skb, sizeof(*header));
+
+		header->size = cpu_to_le16(0);
+		header->vpi = cpu_to_le16(0);
+		header->vci = cpu_to_le16(0);
+		header->type = cpu_to_le16(PKT_STATUS);
+
+		fpga_queue(card, i, skb, NULL);
 	}
 	return 0;
 }
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 09/30] solos: Kill existing connections on link down event
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (8 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 07/30] solos: Add initial list of parameters David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 10/30] solos: Reject non-AAL5 connections.... for now David Woodhouse
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   30 ++++++++++++++++++++++++++++--
 1 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 4c87dfb..c289b62 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -132,6 +132,7 @@ static int fpga_tx(struct solos_card *);
 static irqreturn_t solos_irq(int irq, void *dev_id);
 static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
 static int list_vccs(int vci);
+static void release_vccs(struct atm_dev *dev);
 static int atm_init(struct solos_card *);
 static void atm_remove(struct solos_card *);
 static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
@@ -332,7 +333,10 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 	str = next_string(skb);
 	if (!strcmp(str, "Showtime"))
 		state = ATM_PHY_SIG_FOUND;
-	else state = ATM_PHY_SIG_LOST;
+	else {
+		state = ATM_PHY_SIG_LOST;
+		release_vccs(card->atmdev[port]);
+	}
 
 	card->atmdev[port]->link_rate = rate_down;
 	card->atmdev[port]->signal = state;
@@ -683,7 +687,7 @@ static int list_vccs(int vci)
 			       vcc->vci);
 		}
 	} else {
-		for(i=0; i<32; i++){
+		for(i = 0; i < VCC_HTABLE_SIZE; i++){
 			head = &vcc_hash[i];
 			sk_for_each(s, node, head) {
 				num_found ++;
@@ -699,6 +703,28 @@ static int list_vccs(int vci)
 	return num_found;
 }
 
+static void release_vccs(struct atm_dev *dev)
+{
+        int i;
+
+        write_lock_irq(&vcc_sklist_lock);
+        for (i = 0; i < VCC_HTABLE_SIZE; i++) {
+                struct hlist_head *head = &vcc_hash[i];
+                struct hlist_node *node, *tmp;
+                struct sock *s;
+                struct atm_vcc *vcc;
+
+                sk_for_each_safe(s, node, tmp, head) {
+                        vcc = atm_sk(s);
+                        if (vcc->dev == dev) {
+                                vcc_release_async(vcc, -EPIPE);
+                                sk_del_node_init(s);
+                        }
+                }
+        }
+        write_unlock_irq(&vcc_sklist_lock);
+}
+
 
 static int popen(struct atm_vcc *vcc)
 {
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 10/30] solos: Reject non-AAL5 connections.... for now
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (9 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 09/30] solos: Kill existing connections on link down event David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 11/30] solos: Add SNR and Attn to status packet, fix oops on load David Woodhouse
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index c289b62..b500f00 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -732,6 +732,12 @@ static int popen(struct atm_vcc *vcc)
 	struct sk_buff *skb;
 	struct pkt_hdr *header;
 
+	if (vcc->qos.aal != ATM_AAL5) {
+		dev_warn(&card->dev->dev, "Unsupported ATM type %d\n",
+			 vcc->qos.aal);
+		return -EINVAL;
+	}
+
 	skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
 	if (!skb && net_ratelimit()) {
 		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 11/30] solos: Add SNR and Attn to status packet, fix oops on load
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (10 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 10/30] solos: Reject non-AAL5 connections.... for now David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 12/30] solos: Fix under-allocation of skb size for get/set parameters David Woodhouse
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   30 +++++++++++++++++++++++-------
 1 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index b500f00..2978699 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -303,8 +303,8 @@ static char *next_string(struct sk_buff *skb)
  */       
 static int process_status(struct solos_card *card, int port, struct sk_buff *skb)
 {
-	char *str, *end;
-	int ver, rate_up, rate_down, state;
+	char *str, *end, *state_str;
+	int ver, rate_up, rate_down, state, snr, attn;
 
 	if (!card->atmdev[port])
 		return -ENODEV;
@@ -330,19 +330,35 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 	if (*end)
 		return -EIO;
 
-	str = next_string(skb);
-	if (!strcmp(str, "Showtime"))
+	state_str = next_string(skb);
+	if (!strcmp(state_str, "Showtime"))
 		state = ATM_PHY_SIG_FOUND;
 	else {
 		state = ATM_PHY_SIG_LOST;
 		release_vccs(card->atmdev[port]);
 	}
 
+	str = next_string(skb);
+	snr = simple_strtol(str, &end, 10);
+	if (*end)
+		return -EIO;
+
+	str = next_string(skb);
+	attn = simple_strtol(str, &end, 10);
+	if (*end)
+		return -EIO;
+
+	if (state == ATM_PHY_SIG_LOST && !rate_up && !rate_down)
+		dev_info(&card->dev->dev, "Port %d ATM state: %s\n",
+			 port, state_str);
+	else
+		dev_info(&card->dev->dev, "Port %d ATM state: %s (%d/%d kb/s, SNR %ddB, Attn %ddB)\n",
+			 port, state_str, rate_up/1000, rate_down/1000,
+			 snr, attn);
+
 	card->atmdev[port]->link_rate = rate_down;
 	card->atmdev[port]->signal = state;
 
-	dev_info(&card->dev->dev, "ATM state: '%s', %d/%d kb/s up/down.\n",
-		 str, rate_up/1000, rate_down/1000);
 	return 0;
 }
 
@@ -851,7 +867,7 @@ static int fpga_tx(struct solos_card *card)
 	dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
 
 	for (port = 0; port < card->nr_ports; port++) {
-		if (!(tx_pending & (1 << port))) {
+		if (card->atmdev[port] && !(tx_pending & (1 << port))) {
 
 			spin_lock(&card->tx_queue_lock);
 			skb = skb_dequeue(&card->tx_queue[port]);
-- 
1.6.0.6




^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/30] solos: Fix under-allocation of skb size for get/set parameters
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (11 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 11/30] solos: Add SNR and Attn to status packet, fix oops on load David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 13/30] solos: Remove parameter group from sysfs on ATM dev deregister David Woodhouse
                   ` (17 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 2978699..2dca5ff 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -159,7 +159,7 @@ static ssize_t solos_param_show(struct device *dev, struct device_attribute *att
 
 	buflen = strlen(attr->attr.name) + 10;
 
-	skb = alloc_skb(buflen, GFP_KERNEL);
+	skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL);
 	if (!skb) {
 		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n");
 		return -ENOMEM;
@@ -215,7 +215,7 @@ static ssize_t solos_param_store(struct device *dev, struct device_attribute *at
 
 	buflen = strlen(attr->attr.name) + 11 + count;
 
-	skb = alloc_skb(buflen, GFP_KERNEL);
+	skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL);
 	if (!skb) {
 		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n");
 		return -ENOMEM;
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 13/30] solos: Remove parameter group from sysfs on ATM dev deregister
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (12 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 12/30] solos: Fix under-allocation of skb size for get/set parameters David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 14/30] solos: First attempt at DMA support David Woodhouse
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 2dca5ff..b7d4af3 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -1166,6 +1166,8 @@ static void atm_remove(struct solos_card *card)
 	for (i = 0; i < card->nr_ports; i++) {
 		if (card->atmdev[i]) {
 			dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number);
+
+			sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group);
 			atm_dev_deregister(card->atmdev[i]);
 		}
 	}
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 14/30] solos: First attempt at DMA support
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (13 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 13/30] solos: Remove parameter group from sysfs on ATM dev deregister David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 15/30] solos: Tidy up DMA handling a little. Still untested David Woodhouse
                   ` (15 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |  118 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 90 insertions(+), 28 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index b7d4af3..63c9ad0 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -55,6 +55,8 @@
 #define FLASH_BUSY	0x60
 #define FPGA_MODE	0x5C
 #define FLASH_MODE	0x58
+#define TX_DMA_ADDR(port)	(0x40 + (4 * (port)))
+#define RX_DMA_ADDR(port)	(0x30 + (4 * (port)))
 
 #define DATA_RAM_SIZE	32768
 #define BUF_SIZE	4096
@@ -78,6 +80,14 @@ struct pkt_hdr {
 	__le16 type;
 };
 
+struct solos_skb_cb {
+	struct atm_vcc *vcc;
+	uint32_t dma_addr;
+};
+
+
+#define SKB_CB(skb)		((struct solos_skb_cb *)skb->cb)
+
 #define PKT_DATA	0
 #define PKT_COMMAND	1
 #define PKT_POPEN	3
@@ -98,8 +108,11 @@ struct solos_card {
 	struct list_head param_queue;
 	struct sk_buff_head tx_queue[4];
 	struct sk_buff_head cli_queue[4];
+	struct sk_buff *tx_skb[4];
+	struct sk_buff *rx_skb[4];
 	wait_queue_head_t param_wq;
 	wait_queue_head_t fw_wq;
+	int using_dma;
 };
 

@@ -588,44 +601,64 @@ void solos_bh(unsigned long card_arg)
 
 	for (port = 0; port < card->nr_ports; port++) {
 		if (card_flags & (0x10 << port)) {
-			struct pkt_hdr header;
+			struct pkt_hdr _hdr, *header;
 			struct sk_buff *skb;
 			struct atm_vcc *vcc;
 			int size;
 
-			rx_done |= 0x10 << port;
+			if (card->using_dma) {
+				skb = card->rx_skb[port];
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, skb->len,
+						 PCI_DMA_FROMDEVICE);
+
+				card->rx_skb[port] = alloc_skb(2048, GFP_ATOMIC);
+				if (card->rx_skb[port]) {
+					SKB_CB(card->rx_skb[port])->dma_addr =
+						pci_map_single(card->dev, skb->data, skb->len,
+							       PCI_DMA_FROMDEVICE);
+					iowrite32(SKB_CB(card->rx_skb[port])->dma_addr,
+						  card->config_regs + RX_DMA_ADDR(port));
+				}
+				header = (void *)skb->data;
+				size = le16_to_cpu(header->size);
+				skb_put(skb, size + sizeof(*header));
+				skb_pull(skb, sizeof(*header));
+			} else {
+				header = &_hdr;
 
-			memcpy_fromio(&header, RX_BUF(card, port), sizeof(header));
+				rx_done |= 0x10 << port;
 
-			size = le16_to_cpu(header.size);
+				memcpy_fromio(header, RX_BUF(card, port), sizeof(*header));
 
-			skb = alloc_skb(size + 1, GFP_ATOMIC);
-			if (!skb) {
-				if (net_ratelimit())
-					dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
-				continue;
-			}
+				size = le16_to_cpu(header->size);
 
-			memcpy_fromio(skb_put(skb, size),
-				      RX_BUF(card, port) + sizeof(header),
-				      size);
+				skb = alloc_skb(size + 1, GFP_ATOMIC);
+				if (!skb) {
+					if (net_ratelimit())
+						dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+					continue;
+				}
 
+				memcpy_fromio(skb_put(skb, size),
+					      RX_BUF(card, port) + sizeof(*header),
+					      size);
+			}
 			if (atmdebug) {
 				dev_info(&card->dev->dev, "Received: device %d\n", port);
 				dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
-					 size, le16_to_cpu(header.vpi),
-					 le16_to_cpu(header.vci));
+					 size, le16_to_cpu(header->vpi),
+					 le16_to_cpu(header->vci));
 				print_buffer(skb);
 			}
 
-			switch (le16_to_cpu(header.type)) {
+			switch (le16_to_cpu(header->type)) {
 			case PKT_DATA:
-				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi),
-					       le16_to_cpu(header.vci));
+				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi),
+					       le16_to_cpu(header->vci));
 				if (!vcc) {
 					if (net_ratelimit())
 						dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n",
-							 le16_to_cpu(header.vci), le16_to_cpu(header.vpi),
+							 le16_to_cpu(header->vci), le16_to_cpu(header->vpi),
 							 port);
 					continue;
 				}
@@ -839,7 +872,7 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 {
 	int old_len;
 
-	*(void **)skb->cb = vcc;
+	SKB_CB(skb)->vcc = vcc;
 
 	spin_lock(&card->tx_queue_lock);
 	old_len = skb_queue_len(&card->tx_queue[port]);
@@ -881,17 +914,37 @@ static int fpga_tx(struct solos_card *card)
 					 port);
 				print_buffer(skb);
 			}
-			memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
+			if (card->using_dma) {
+				if (card->tx_skb[port]) {
+					struct sk_buff *oldskb = card->tx_skb[port];
 
-			vcc = *(void **)skb->cb;
+					pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
+							 oldskb->len, PCI_DMA_TODEVICE);
 
-			if (vcc) {
-				atomic_inc(&vcc->stats->tx);
-				solos_pop(vcc, skb);
-			} else
-				dev_kfree_skb_irq(skb);
+					vcc = SKB_CB(oldskb)->vcc;
 
-			tx_started |= 1 << port; //Set TX full flag
+					if (vcc) {
+						atomic_inc(&vcc->stats->tx);
+						solos_pop(vcc, oldskb);
+					} else
+						dev_kfree_skb_irq(oldskb);
+				}
+
+				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
+							       skb->len, PCI_DMA_TODEVICE);
+				iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port));
+			} else {
+				memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
+				tx_started |= 1 << port; //Set TX full flag
+
+				vcc = SKB_CB(skb)->vcc;
+
+				if (vcc) {
+					atomic_inc(&vcc->stats->tx);
+					solos_pop(vcc, skb);
+				} else
+					dev_kfree_skb_irq(skb);
+			}
 		}
 	}
 	if (tx_started)
@@ -999,6 +1052,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto out;
 	}
 
+	err = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+	if (err) {
+		dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n");
+		goto out;
+	}
+
 	err = pci_request_regions(dev, "solos");
 	if (err) {
 		dev_warn(&dev->dev, "Failed to request regions\n");
@@ -1035,6 +1094,9 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
 		 major_ver, minor_ver, fpga_ver);
 
+	if (fpga_ver > 27)
+		card->using_dma = 1;
+
 	card->nr_ports = 2; /* FIXME: Detect daughterboard */
 
 	pci_set_drvdata(dev, card);
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 15/30] solos: Tidy up DMA handling a little. Still untested
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (14 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 14/30] solos: First attempt at DMA support David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 16/30] solos: Tidy up tx_mask handling for ports which need TX David Woodhouse
                   ` (14 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   95 ++++++++++++++++++++++++++---------------------
 1 files changed, 53 insertions(+), 42 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 63c9ad0..acba08d 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -68,6 +68,8 @@
 #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
 #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)
 
+#define RX_DMA_SIZE	2048
+
 static int debug = 0;
 static int atmdebug = 0;
 static int firmware_upgrade = 0;
@@ -608,17 +610,11 @@ void solos_bh(unsigned long card_arg)
 
 			if (card->using_dma) {
 				skb = card->rx_skb[port];
-				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, skb->len,
-						 PCI_DMA_FROMDEVICE);
-
-				card->rx_skb[port] = alloc_skb(2048, GFP_ATOMIC);
-				if (card->rx_skb[port]) {
-					SKB_CB(card->rx_skb[port])->dma_addr =
-						pci_map_single(card->dev, skb->data, skb->len,
-							       PCI_DMA_FROMDEVICE);
-					iowrite32(SKB_CB(card->rx_skb[port])->dma_addr,
-						  card->config_regs + RX_DMA_ADDR(port));
-				}
+				card->rx_skb[port] = NULL;
+
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+						 RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+
 				header = (void *)skb->data;
 				size = le16_to_cpu(header->size);
 				skb_put(skb, size + sizeof(*header));
@@ -669,7 +665,7 @@ void solos_bh(unsigned long card_arg)
 
 			case PKT_STATUS:
 				process_status(card, port, skb);
-				dev_kfree_skb(skb);
+				dev_kfree_skb_any(skb);
 				break;
 
 			case PKT_COMMAND:
@@ -681,12 +677,32 @@ void solos_bh(unsigned long card_arg)
 					if (net_ratelimit())
 						dev_warn(&card->dev->dev, "Dropping console response on port %d\n",
 							 port);
+					dev_kfree_skb_any(skb);
 				} else
 					skb_queue_tail(&card->cli_queue[port], skb);
 				spin_unlock(&card->cli_queue_lock);
 				break;
 			}
 		}
+		/* Allocate RX skbs for any ports which need them */
+		if (card->using_dma && card->atmdev[port] &&
+		    !card->rx_skb[port]) {
+			struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC);
+			if (skb) {
+				SKB_CB(skb)->dma_addr =
+					pci_map_single(card->dev, skb->data,
+						       RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+				iowrite32(SKB_CB(skb)->dma_addr,
+					  card->config_regs + RX_DMA_ADDR(port));
+				card->rx_skb[port] = skb;
+			} else {
+				if (net_ratelimit())
+					dev_warn(&card->dev->dev, "Failed to allocate RX skb");
+
+				/* We'll have to try again later */
+				tasklet_schedule(&card->tlet);
+			}
+		}
 	}
 	if (rx_done)
 		iowrite32(rx_done, card->config_regs + FLAGS_ADDR);
@@ -901,50 +917,45 @@ static int fpga_tx(struct solos_card *card)
 
 	for (port = 0; port < card->nr_ports; port++) {
 		if (card->atmdev[port] && !(tx_pending & (1 << port))) {
+			struct sk_buff *oldskb = card->tx_skb[port];
 
+			if (oldskb)
+				pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
+						 oldskb->len, PCI_DMA_TODEVICE);
+			
 			spin_lock(&card->tx_queue_lock);
 			skb = skb_dequeue(&card->tx_queue[port]);
 			spin_unlock(&card->tx_queue_lock);
 
-			if (!skb)
+			if (skb && !card->using_dma) {
+				memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
+				tx_started |= 1 << port; //Set TX full flag
+				oldskb = skb; /* We're done with this skb already */
+			} else if (skb && card->using_dma) {
+				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
+								       skb->len, PCI_DMA_TODEVICE);
+				iowrite32(SKB_CB(skb)->dma_addr,
+					  card->config_regs + TX_DMA_ADDR(port));
+			}
+
+			if (!oldskb)
 				continue;
 
+			/* Clean up and free oldskb now it's gone */
 			if (atmdebug) {
 				dev_info(&card->dev->dev, "Transmitted: port %d\n",
 					 port);
-				print_buffer(skb);
+				print_buffer(oldskb);
 			}
-			if (card->using_dma) {
-				if (card->tx_skb[port]) {
-					struct sk_buff *oldskb = card->tx_skb[port];
-
-					pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
-							 oldskb->len, PCI_DMA_TODEVICE);
-
-					vcc = SKB_CB(oldskb)->vcc;
-
-					if (vcc) {
-						atomic_inc(&vcc->stats->tx);
-						solos_pop(vcc, oldskb);
-					} else
-						dev_kfree_skb_irq(oldskb);
-				}
 
-				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
-							       skb->len, PCI_DMA_TODEVICE);
-				iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port));
-			} else {
-				memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
-				tx_started |= 1 << port; //Set TX full flag
+			vcc = SKB_CB(oldskb)->vcc;
 
-				vcc = SKB_CB(skb)->vcc;
+			if (vcc) {
+				atomic_inc(&vcc->stats->tx);
+				solos_pop(vcc, oldskb);
+			} else
+				dev_kfree_skb_irq(oldskb);
 
-				if (vcc) {
-					atomic_inc(&vcc->stats->tx);
-					solos_pop(vcc, skb);
-				} else
-					dev_kfree_skb_irq(skb);
-			}
 		}
 	}
 	if (tx_started)
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 16/30] solos: Tidy up tx_mask handling for ports which need TX
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (15 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 15/30] solos: Tidy up DMA handling a little. Still untested David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 17/30] solos: Remove unused loopback debug stuff David Woodhouse
                   ` (13 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index acba08d..bf59c40 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -100,6 +100,7 @@ struct solos_card {
 	void __iomem *config_regs;
 	void __iomem *buffers;
 	int nr_ports;
+	int tx_mask;
 	struct pci_dev *dev;
 	struct atm_dev *atmdev[4];
 	struct tasklet_struct tlet;
@@ -590,15 +591,13 @@ void solos_bh(unsigned long card_arg)
 	struct solos_card *card = (void *)card_arg;
 	int port;
 	uint32_t card_flags;
-	uint32_t tx_mask;
 	uint32_t rx_done = 0;
 
 	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
 
 	/* The TX bits are set if the channel is busy; clear if not. We want to
 	   invoke fpga_tx() unless _all_ the bits for active channels are set */
-	tx_mask = (1 << card->nr_ports) - 1;
-	if ((card_flags & tx_mask) != tx_mask)
+	if ((card_flags & card->tx_mask) != card->tx_mask)
 		fpga_tx(card);
 
 	for (port = 0; port < card->nr_ports; port++) {
@@ -887,15 +886,20 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc)
 {
 	int old_len;
+	unsigned long flags;
 
 	SKB_CB(skb)->vcc = vcc;
 
-	spin_lock(&card->tx_queue_lock);
+	spin_lock_irqsave(&card->tx_queue_lock, flags);
 	old_len = skb_queue_len(&card->tx_queue[port]);
 	skb_queue_tail(&card->tx_queue[port], skb);
-	spin_unlock(&card->tx_queue_lock);
+	if (!old_len) {
+		card->tx_mask |= (1 << port);
+	}
+	spin_unlock_irqrestore(&card->tx_queue_lock, flags);
 
-	/* If TX might need to be started, do so */
+	/* Theoretically we could just schedule the tasklet here, but
+	   that introduces latency we don't want -- it's noticeable */
 	if (!old_len)
 		fpga_tx(card);
 }
@@ -911,7 +915,7 @@ static int fpga_tx(struct solos_card *card)
 
 	spin_lock_irqsave(&card->tx_lock, flags);
 
-	tx_pending = ioread32(card->config_regs + FLAGS_ADDR);
+	tx_pending = ioread32(card->config_regs + FLAGS_ADDR) & card->tx_mask;
 
 	dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
 
@@ -925,6 +929,8 @@ static int fpga_tx(struct solos_card *card)
 			
 			spin_lock(&card->tx_queue_lock);
 			skb = skb_dequeue(&card->tx_queue[port]);
+			if (!skb)
+				card->tx_mask &= ~(1 << port);
 			spin_unlock(&card->tx_queue_lock);
 
 			if (skb && !card->using_dma) {
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 18/30] solos: Remove IRQF_DISABLED, don't frob IRQ enable on the FPGA in solos_irq()
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (17 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 17/30] solos: Remove unused loopback debug stuff David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 19/30] solos: Remove superfluous wait_queue_head_t from struct solos_param David Woodhouse
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Neither of these are necessary.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 2ef8157..f2736dd 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -570,16 +570,12 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
 
 	//ACK IRQ
 	iowrite32(0, card->config_regs + IRQ_CLEAR);
-	//Disable IRQs from FPGA
-	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
 	if (card->atmdev[0])
 		tasklet_schedule(&card->tlet);
 	else
 		wake_up(&card->fw_wq);
 
-	//Enable IRQs from FPGA
-	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 	return IRQ_RETVAL(handled);
 }
 
@@ -1132,7 +1128,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	}
 */
 	//dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq);
-	err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED,
+	err = request_irq(dev->irq, solos_irq, IRQF_SHARED,
 			  "solos-pci", card);
 	if (err) {
 		dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq);
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 17/30] solos: Remove unused loopback debug stuff
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (16 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 16/30] solos: Tidy up tx_mask handling for ports which need TX David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 18/30] solos: Remove IRQF_DISABLED, don't frob IRQ enable on the FPGA in solos_irq() David Woodhouse
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   23 -----------------------
 1 files changed, 0 insertions(+), 23 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index bf59c40..2ef8157 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -70,7 +70,6 @@
 
 #define RX_DMA_SIZE	2048
 
-static int debug = 0;
 static int atmdebug = 0;
 static int firmware_upgrade = 0;
 static int fpga_upgrade = 0;
@@ -133,11 +132,9 @@ MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
 MODULE_DESCRIPTION("Solos PCI driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(debug, "Enable Loopback");
 MODULE_PARM_DESC(atmdebug, "Print ATM data");
 MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
 MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
-module_param(debug, int, 0444);
 module_param(atmdebug, int, 0644);
 module_param(firmware_upgrade, int, 0444);
 module_param(fpga_upgrade, int, 0444);
@@ -974,26 +971,12 @@ static int fpga_tx(struct solos_card *card)
 static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 {
 	struct solos_card *card = vcc->dev->dev_data;
-	struct sk_buff *skb2 = NULL;
 	struct pkt_hdr *header;
 	int pktlen;
 
 	//dev_dbg(&card->dev->dev, "psend called.\n");
 	//dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci);
 
-	if (debug) {
-		skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC);
-		if (skb2) {
-			memcpy(skb2->data, skb->data, skb->len);
-			skb_put(skb2, skb->len);
-			vcc->push(vcc, skb2);
-			atomic_inc(&vcc->stats->rx);
-		}
-		atomic_inc(&vcc->stats->tx);
-		solos_pop(vcc, skb);
-		return 0;
-	}
-
 	pktlen = skb->len;
 	if (pktlen > (BUF_SIZE - sizeof(*header))) {
 		dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n");
@@ -1052,9 +1035,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	uint32_t data32;
 	struct solos_card *card;
 
-	if (debug)
-		return 0;
-
 	card = kzalloc(sizeof(*card), GFP_KERNEL);
 	if (!card)
 		return -ENOMEM;
@@ -1256,9 +1236,6 @@ static void fpga_remove(struct pci_dev *dev)
 {
 	struct solos_card *card = pci_get_drvdata(dev);
 
-	if (debug)
-		return;
-
 	atm_remove(card);
 
 	dev_vdbg(&dev->dev, "Freeing IRQ\n");
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 19/30] solos: Remove superfluous wait_queue_head_t from struct solos_param
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (18 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 18/30] solos: Remove IRQF_DISABLED, don't frob IRQ enable on the FPGA in solos_irq() David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 20/30] solos: Fix various bugs in status packet handling David Woodhouse
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index f2736dd..8121f85 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -123,7 +123,6 @@ struct solos_param {
 	pid_t pid;
 	int port;
 	struct sk_buff *response;
-	wait_queue_head_t wq;
 };
 
 #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 20/30] solos: Fix various bugs in status packet handling
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (19 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 19/30] solos: Remove superfluous wait_queue_head_t from struct solos_param David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 21/30] solos: Clean up handling of card->tx_mask a little David Woodhouse
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   49 ++++++++++++++++++++++++++--------------------
 1 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 8121f85..5e228a3 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -293,13 +293,15 @@ static char *next_string(struct sk_buff *skb)
 {
 	int i = 0;
 	char *this = skb->data;
-
-	while (i < skb->len) {
+	
+	for (i = 0; i < skb->len; i++) {
 		if (this[i] == '\n') {
 			this[i] = 0;
-			skb_pull(skb, i);
+			skb_pull(skb, i + 1);
 			return this;
 		}
+		if (!isprint(this[i]))
+			return NULL;
 	}
 	return NULL;
 }
@@ -316,7 +318,7 @@ static char *next_string(struct sk_buff *skb)
 static int process_status(struct solos_card *card, int port, struct sk_buff *skb)
 {
 	char *str, *end, *state_str;
-	int ver, rate_up, rate_down, state, snr, attn;
+	int ver, rate_up, rate_down, state;
 
 	if (!card->atmdev[port])
 		return -ENODEV;
@@ -333,16 +335,22 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 	}
 
 	str = next_string(skb);
+	if (!str)
+		return -EIO;
 	rate_up = simple_strtol(str, &end, 10);
 	if (*end)
 		return -EIO;
 
 	str = next_string(skb);
+	if (!str)
+		return -EIO;
 	rate_down = simple_strtol(str, &end, 10);
 	if (*end)
 		return -EIO;
 
 	state_str = next_string(skb);
+	if (!state_str)
+		return -EIO;
 	if (!strcmp(state_str, "Showtime"))
 		state = ATM_PHY_SIG_FOUND;
 	else {
@@ -350,25 +358,24 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 		release_vccs(card->atmdev[port]);
 	}
 
-	str = next_string(skb);
-	snr = simple_strtol(str, &end, 10);
-	if (*end)
-		return -EIO;
-
-	str = next_string(skb);
-	attn = simple_strtol(str, &end, 10);
-	if (*end)
-		return -EIO;
-
-	if (state == ATM_PHY_SIG_LOST && !rate_up && !rate_down)
+	if (state == ATM_PHY_SIG_LOST) {
 		dev_info(&card->dev->dev, "Port %d ATM state: %s\n",
 			 port, state_str);
-	else
-		dev_info(&card->dev->dev, "Port %d ATM state: %s (%d/%d kb/s, SNR %ddB, Attn %ddB)\n",
-			 port, state_str, rate_up/1000, rate_down/1000,
-			 snr, attn);
-
-	card->atmdev[port]->link_rate = rate_down;
+	} else {
+		char *snr, *attn;
+
+		snr = next_string(skb);
+		if (!str)
+			return -EIO;
+		attn = next_string(skb);
+		if (!attn)
+			return -EIO;
+
+		dev_info(&card->dev->dev, "Port %d: %s (%d/%d kb/s%s%s%s%s)\n",
+			 port, state_str, rate_down/1000, rate_up/1000,
+			 snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
+	}		
+	card->atmdev[port]->link_rate = rate_down / 424;
 	card->atmdev[port]->signal = state;
 
 	return 0;
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 21/30] solos: Clean up handling of card->tx_mask a little
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (20 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 20/30] solos: Fix various bugs in status packet handling David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 22/30] solos: Remove debugging, commented-out test code David Woodhouse
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   53 ++++++++++++++++++++++++----------------------
 1 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 5e228a3..e7691b3 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -140,7 +140,7 @@ module_param(fpga_upgrade, int, 0444);
 
 static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		       struct atm_vcc *vcc);
-static int fpga_tx(struct solos_card *);
+static uint32_t fpga_tx(struct solos_card *);
 static irqreturn_t solos_irq(int irq, void *dev_id);
 static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
 static int list_vccs(int vci);
@@ -438,8 +438,6 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_
 	struct sk_buff *skb;
 	struct pkt_hdr *header;
 
-//	dev_dbg(&card->dev->dev, "size: %d\n", size);
-
 	if (size > (BUF_SIZE - sizeof(*header))) {
 		dev_dbg(&card->dev->dev, "Command is too big.  Dropping request\n");
 		return 0;
@@ -574,9 +572,9 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
 	struct solos_card *card = dev_id;
 	int handled = 1;
 
-	//ACK IRQ
 	iowrite32(0, card->config_regs + IRQ_CLEAR);
 
+	/* If we're up and running, just kick the tasklet to process TX/RX */
 	if (card->atmdev[0])
 		tasklet_schedule(&card->tlet);
 	else
@@ -588,16 +586,16 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
 void solos_bh(unsigned long card_arg)
 {
 	struct solos_card *card = (void *)card_arg;
-	int port;
 	uint32_t card_flags;
 	uint32_t rx_done = 0;
+	int port;
 
-	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
-
-	/* The TX bits are set if the channel is busy; clear if not. We want to
-	   invoke fpga_tx() unless _all_ the bits for active channels are set */
-	if ((card_flags & card->tx_mask) != card->tx_mask)
-		fpga_tx(card);
+	/*
+	 * Since fpga_tx() is going to need to read the flags under its lock,
+	 * it can return them to us so that we don't have to hit PCI MMIO
+	 * again for the same information
+	 */
+	card_flags = fpga_tx(card);
 
 	for (port = 0; port < card->nr_ports; port++) {
 		if (card_flags & (0x10 << port)) {
@@ -892,9 +890,8 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 	spin_lock_irqsave(&card->tx_queue_lock, flags);
 	old_len = skb_queue_len(&card->tx_queue[port]);
 	skb_queue_tail(&card->tx_queue[port], skb);
-	if (!old_len) {
+	if (!old_len)
 		card->tx_mask |= (1 << port);
-	}
 	spin_unlock_irqrestore(&card->tx_queue_lock, flags);
 
 	/* Theoretically we could just schedule the tasklet here, but
@@ -903,9 +900,9 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
 		fpga_tx(card);
 }
 
-static int fpga_tx(struct solos_card *card)
+static uint32_t fpga_tx(struct solos_card *card)
 {
-	uint32_t tx_pending;
+	uint32_t tx_pending, card_flags;
 	uint32_t tx_started = 0;
 	struct sk_buff *skb;
 	struct atm_vcc *vcc;
@@ -913,19 +910,24 @@ static int fpga_tx(struct solos_card *card)
 	unsigned long flags;
 
 	spin_lock_irqsave(&card->tx_lock, flags);
-
-	tx_pending = ioread32(card->config_regs + FLAGS_ADDR) & card->tx_mask;
-
-	dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
-
-	for (port = 0; port < card->nr_ports; port++) {
-		if (card->atmdev[port] && !(tx_pending & (1 << port))) {
+	
+	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
+	/*
+	 * The queue lock is required for _writing_ to tx_mask, but we're
+	 * OK to read it here without locking. The only potential update
+	 * that we could race with is in fpga_queue() where it sets a bit
+	 * for a new port... but it's going to call this function again if
+	 * it's doing that, anyway.
+	 */
+	tx_pending = card->tx_mask & ~card_flags;
+
+	for (port = 0; tx_pending; tx_pending >>= 1, port++) {
+		if (tx_pending & 1) {
 			struct sk_buff *oldskb = card->tx_skb[port];
-
 			if (oldskb)
 				pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
 						 oldskb->len, PCI_DMA_TODEVICE);
-			
+
 			spin_lock(&card->tx_queue_lock);
 			skb = skb_dequeue(&card->tx_queue[port]);
 			if (!skb)
@@ -966,8 +968,9 @@ static int fpga_tx(struct solos_card *card)
 	if (tx_started)
 		iowrite32(tx_started, card->config_regs + FLAGS_ADDR);
 
+ out:
 	spin_unlock_irqrestore(&card->tx_lock, flags);
-	return 0;
+	return card_flags;
 }
 
 static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 23/30] solos: Add 'reset' module parameter to reset the DSL chips on load
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (22 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 22/30] solos: Remove debugging, commented-out test code David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 24/30] solos: Tidy up status interrupt handling, cope with 'ERROR' status David Woodhouse
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 21c73b1..c54eceb 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -70,6 +70,7 @@
 
 #define RX_DMA_SIZE	2048
 
+static int reset = 0;
 static int atmdebug = 0;
 static int firmware_upgrade = 0;
 static int fpga_upgrade = 0;
@@ -131,9 +132,11 @@ MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
 MODULE_DESCRIPTION("Solos PCI driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(reset, "Reset Solos chips on startup");
 MODULE_PARM_DESC(atmdebug, "Print ATM data");
 MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
 MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
+module_param(reset, int, 0444);
 module_param(atmdebug, int, 0644);
 module_param(firmware_upgrade, int, 0444);
 module_param(fpga_upgrade, int, 0444);
@@ -1071,6 +1074,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto out_unmap_config;
 	}
 
+	if (reset) {
+		iowrite32(1, card->config_regs + FPGA_MODE);
+		data32 = ioread32(card->config_regs + FPGA_MODE); 
+
+		iowrite32(0, card->config_regs + FPGA_MODE);
+		data32 = ioread32(card->config_regs + FPGA_MODE); 
+	}
 	//Fill Config Mem with zeros
 	for(i = 0; i < 128; i += 4)
 		iowrite32(0, card->config_regs + i);
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 22/30] solos: Remove debugging, commented-out test code
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (21 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 21/30] solos: Clean up handling of card->tx_mask a little David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 23/30] solos: Add 'reset' module parameter to reset the DSL chips on load David Woodhouse
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   52 ++--------------------------------------------
 1 files changed, 3 insertions(+), 49 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index e7691b3..21c73b1 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -813,8 +813,7 @@ static int popen(struct atm_vcc *vcc)
 
 	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
-//	dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-	set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci
+	set_bit(ATM_VF_ADDR, &vcc->flags);
 	set_bit(ATM_VF_READY, &vcc->flags);
 	list_vccs(0);
 
@@ -842,8 +841,6 @@ static void pclose(struct atm_vcc *vcc)
 
 	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
-//	dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-
 	clear_bit(ATM_VF_ADDR, &vcc->flags);
 	clear_bit(ATM_VF_READY, &vcc->flags);
 
@@ -936,7 +933,7 @@ static uint32_t fpga_tx(struct solos_card *card)
 
 			if (skb && !card->using_dma) {
 				memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
-				tx_started |= 1 << port; //Set TX full flag
+				tx_started |= 1 << port;
 				oldskb = skb; /* We're done with this skb already */
 			} else if (skb && card->using_dma) {
 				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
@@ -965,10 +962,10 @@ static uint32_t fpga_tx(struct solos_card *card)
 
 		}
 	}
+	/* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */
 	if (tx_started)
 		iowrite32(tx_started, card->config_regs + FLAGS_ADDR);
 
- out:
 	spin_unlock_irqrestore(&card->tx_lock, flags);
 	return card_flags;
 }
@@ -979,9 +976,6 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 	struct pkt_hdr *header;
 	int pktlen;
 
-	//dev_dbg(&card->dev->dev, "psend called.\n");
-	//dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci);
-
 	pktlen = skb->len;
 	if (pktlen > (BUF_SIZE - sizeof(*header))) {
 		dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n");
@@ -1077,11 +1071,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto out_unmap_config;
 	}
 
-//	for(i=0;i<64 ;i+=4){
-//		data32=ioread32(card->buffers + i);
-//		dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32);
-//	}
-
 	//Fill Config Mem with zeros
 	for(i = 0; i < 128; i += 4)
 		iowrite32(0, card->config_regs + i);
@@ -1110,33 +1099,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	spin_lock_init(&card->param_queue_lock);
 	INIT_LIST_HEAD(&card->param_queue);
 
-/*
-	// Set Loopback mode
-	data32 = 0x00010000;
-	iowrite32(data32,card->config_regs + FLAGS_ADDR);
-*/
-/*
-	// Fill Buffers with zeros
-	for (i = 0; i < BUF_SIZE * 8; i += 4)
-		iowrite32(0, card->buffers + i);
-*/
-/*
-	for(i = 0; i < (BUF_SIZE * 1); i += 4)
-		iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE));
-	for(i = 0; i < (BUF_SIZE * 1); i += 4)
-		iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE));
-
-	// Read Config Memory
-	printk(KERN_DEBUG "Reading Config MEM\n");
-	i = 0;
-	for(i = 0; i < 16; i++) {
-		data32=ioread32(card->buffers + i*(BUF_SIZE/2));
-		printk(KERN_ALERT "Addr: %lX Data: %08lX\n",
-		       (unsigned long)(addr_start + i*(BUF_SIZE/2)),
-		       (unsigned long)data32);
-	}
-*/
-	//dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq);
 	err = request_irq(dev->irq, solos_irq, IRQF_SHARED,
 			  "solos-pci", card);
 	if (err) {
@@ -1144,7 +1106,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto out_unmap_both;
 	}
 
-	// Enable IRQs
 	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 
 	if (fpga_upgrade)
@@ -1243,25 +1204,18 @@ static void fpga_remove(struct pci_dev *dev)
 
 	atm_remove(card);
 
-	dev_vdbg(&dev->dev, "Freeing IRQ\n");
-	// Disable IRQs from FPGA
 	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 	free_irq(dev->irq, card);
 	tasklet_kill(&card->tlet);
 
-	//	iowrite32(0x01,pciregs);
-	dev_vdbg(&dev->dev, "Unmapping PCI resource\n");
 	pci_iounmap(dev, card->buffers);
 	pci_iounmap(dev, card->config_regs);
 
-	dev_vdbg(&dev->dev, "Releasing PCI Region\n");
 	pci_release_regions(dev);
 	pci_disable_device(dev);
 
 	pci_set_drvdata(dev, NULL);
 	kfree(card);
-//	dev_dbg(&card->dev->dev, "fpga_remove\n");
-	return;
 }
 
 static struct pci_device_id fpga_pci_tbl[] __devinitdata = {
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 24/30] solos: Tidy up status interrupt handling, cope with 'ERROR' status
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (23 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 23/30] solos: Add 'reset' module parameter to reset the DSL chips on load David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 26/30] solos: Set RX empty flag at startup only for !dma mode David Woodhouse
                   ` (5 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index c54eceb..f27bd92 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -340,6 +340,12 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 	str = next_string(skb);
 	if (!str)
 		return -EIO;
+	if (!strcmp(str, "ERROR")) {
+		dev_dbg(&card->dev->dev, "Status packet indicated Solos error on port %d (starting up?)\n",
+			 port);
+		return 0;
+	}
+
 	rate_up = simple_strtol(str, &end, 10);
 	if (*end)
 		return -EIO;
@@ -362,8 +368,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 	}
 
 	if (state == ATM_PHY_SIG_LOST) {
-		dev_info(&card->dev->dev, "Port %d ATM state: %s\n",
-			 port, state_str);
+		dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
 	} else {
 		char *snr, *attn;
 
@@ -374,7 +379,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 		if (!attn)
 			return -EIO;
 
-		dev_info(&card->dev->dev, "Port %d: %s (%d/%d kb/s%s%s%s%s)\n",
+		dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n",
 			 port, state_str, rate_down/1000, rate_up/1000,
 			 snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
 	}		
@@ -663,7 +668,11 @@ void solos_bh(unsigned long card_arg)
 				break;
 
 			case PKT_STATUS:
-				process_status(card, port, skb);
+				if (process_status(card, port, skb) &&
+				    net_ratelimit()) {
+					dev_warn(&card->dev->dev, "Bad status packet of %d bytes on port %d:\n", skb->len, port);
+					print_buffer(skb);
+				}
 				dev_kfree_skb_any(skb);
 				break;
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 26/30] solos: Set RX empty flag at startup only for !dma mode
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (24 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 24/30] solos: Tidy up status interrupt handling, cope with 'ERROR' status David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 25/30] solos: Don't clear config registers at startup David Woodhouse
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index df01682..7c26bd2 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -1090,8 +1090,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		iowrite32(0, card->config_regs + FPGA_MODE);
 		data32 = ioread32(card->config_regs + FPGA_MODE); 
 	}
-	//Set RX empty flags
-	iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
 
 	data32 = ioread32(card->config_regs + FPGA_VER);
 	fpga_ver = (data32 & 0x0000FFFF);
@@ -1102,6 +1100,10 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	if (fpga_ver > 27)
 		card->using_dma = 1;
+	else {
+		/* Set RX empty flag for all ports */
+		iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
+	}
 
 	card->nr_ports = 2; /* FIXME: Detect daughterboard */
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 25/30] solos: Don't clear config registers at startup
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (25 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 26/30] solos: Set RX empty flag at startup only for !dma mode David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 27/30] solos: Swap upstream/downstream rates in status packet, clean up some more David Woodhouse
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index f27bd92..df01682 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -1040,7 +1040,7 @@ static struct atmdev_ops fpga_ops = {
 
 static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	int err, i;
+	int err;
 	uint16_t fpga_ver;
 	uint8_t major_ver, minor_ver;
 	uint32_t data32;
@@ -1090,10 +1090,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		iowrite32(0, card->config_regs + FPGA_MODE);
 		data32 = ioread32(card->config_regs + FPGA_MODE); 
 	}
-	//Fill Config Mem with zeros
-	for(i = 0; i < 128; i += 4)
-		iowrite32(0, card->config_regs + i);
-
 	//Set RX empty flags
 	iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 27/30] solos: Swap upstream/downstream rates in status packet, clean up some more
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (26 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 25/30] solos: Don't clear config registers at startup David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 28/30] solos: Reset device on unload, free pending skbs David Woodhouse
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   51 +++++++++++++++++++++++------------------------
 1 files changed, 25 insertions(+), 26 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 7c26bd2..eef920a 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -314,14 +314,16 @@ static char *next_string(struct sk_buff *skb)
  * for the information therein. Fields are....
  *
  *     packet version
- *     TxBitRate	(version >= 1)
  *     RxBitRate	(version >= 1)
+ *     TxBitRate	(version >= 1)
  *     State		(version >= 1)
+ *     LocalSNRMargin	(version >= 1)
+ *     LocalLineAttn	(version >= 1)
  */       
 static int process_status(struct solos_card *card, int port, struct sk_buff *skb)
 {
-	char *str, *end, *state_str;
-	int ver, rate_up, rate_down, state;
+	char *str, *end, *state_str, *snr, *attn;
+	int ver, rate_up, rate_down;
 
 	if (!card->atmdev[port])
 		return -ENODEV;
@@ -346,45 +348,42 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
 		return 0;
 	}
 
-	rate_up = simple_strtol(str, &end, 10);
+	rate_down = simple_strtol(str, &end, 10);
 	if (*end)
 		return -EIO;
 
 	str = next_string(skb);
 	if (!str)
 		return -EIO;
-	rate_down = simple_strtol(str, &end, 10);
+	rate_up = simple_strtol(str, &end, 10);
 	if (*end)
 		return -EIO;
 
 	state_str = next_string(skb);
 	if (!state_str)
 		return -EIO;
-	if (!strcmp(state_str, "Showtime"))
-		state = ATM_PHY_SIG_FOUND;
-	else {
-		state = ATM_PHY_SIG_LOST;
+
+	/* Anything but 'Showtime' is down */
+	if (strcmp(state_str, "Showtime")) {
+		card->atmdev[port]->signal = ATM_PHY_SIG_LOST;
 		release_vccs(card->atmdev[port]);
+		dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
+		return 0;
 	}
 
-	if (state == ATM_PHY_SIG_LOST) {
-		dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
-	} else {
-		char *snr, *attn;
-
-		snr = next_string(skb);
-		if (!str)
-			return -EIO;
-		attn = next_string(skb);
-		if (!attn)
-			return -EIO;
-
-		dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n",
-			 port, state_str, rate_down/1000, rate_up/1000,
-			 snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
-	}		
+	snr = next_string(skb);
+	if (!str)
+		return -EIO;
+	attn = next_string(skb);
+	if (!attn)
+		return -EIO;
+
+	dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n",
+		 port, state_str, rate_down/1000, rate_up/1000,
+		 snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
+	
 	card->atmdev[port]->link_rate = rate_down / 424;
-	card->atmdev[port]->signal = state;
+	card->atmdev[port]->signal = ATM_PHY_SIG_FOUND;
 
 	return 0;
 }
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 28/30] solos: Reset device on unload, free pending skbs
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (27 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 27/30] solos: Swap upstream/downstream rates in status packet, clean up some more David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 29/30] solos: Automatically determine number of ports David Woodhouse
  2009-03-17 21:29 ` [PATCH 30/30] solos: Disable DMA until we have an FPGA update with it actually implemented David Woodhouse
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |   30 +++++++++++++++++++++++++++++-
 1 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index eef920a..1ff7304 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -1206,10 +1206,28 @@ static void atm_remove(struct solos_card *card)
 
 	for (i = 0; i < card->nr_ports; i++) {
 		if (card->atmdev[i]) {
+			struct sk_buff *skb;
+
 			dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number);
 
 			sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group);
 			atm_dev_deregister(card->atmdev[i]);
+
+			skb = card->rx_skb[i];
+			if (skb) {
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+						 RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(skb);
+			}
+			skb = card->tx_skb[i];
+			if (skb) {
+				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb(skb);
+			}
+			while ((skb = skb_dequeue(&card->tx_queue[i])))
+				dev_kfree_skb(skb);
+ 
 		}
 	}
 }
@@ -1217,13 +1235,23 @@ static void atm_remove(struct solos_card *card)
 static void fpga_remove(struct pci_dev *dev)
 {
 	struct solos_card *card = pci_get_drvdata(dev);
+	
+	/* Disable IRQs */
+	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+
+	/* Reset FPGA */
+	iowrite32(1, card->config_regs + FPGA_MODE);
+	(void)ioread32(card->config_regs + FPGA_MODE); 
 
 	atm_remove(card);
 
-	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 	free_irq(dev->irq, card);
 	tasklet_kill(&card->tlet);
 
+	/* Release device from reset */
+	iowrite32(0, card->config_regs + FPGA_MODE);
+	(void)ioread32(card->config_regs + FPGA_MODE); 
+
 	pci_iounmap(dev, card->buffers);
 	pci_iounmap(dev, card->config_regs);
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 29/30] solos: Automatically determine number of ports
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (28 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 28/30] solos: Reset device on unload, free pending skbs David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  2009-03-17 21:29 ` [PATCH 30/30] solos: Disable DMA until we have an FPGA update with it actually implemented David Woodhouse
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: Nathan Williams <nathan@traverse.com.au>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 1ff7304..6fe8f8f 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -1104,7 +1104,8 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
 	}
 
-	card->nr_ports = 2; /* FIXME: Detect daughterboard */
+	data32 = ioread32(card->config_regs + PORTS);
+	card->nr_ports = (data32 & 0x000000FF);
 
 	pci_set_drvdata(dev, card);
 
-- 
1.6.0.6



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 30/30] solos: Disable DMA until we have an FPGA update with it actually implemented.
  2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
                   ` (29 preceding siblings ...)
  2009-03-17 21:29 ` [PATCH 29/30] solos: Automatically determine number of ports David Woodhouse
@ 2009-03-17 21:29 ` David Woodhouse
  30 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:29 UTC (permalink / raw)
  To: netdev

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
---
 drivers/atm/solos-pci.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 6fe8f8f..bc3079d 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -1097,7 +1097,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
 		 major_ver, minor_ver, fpga_ver);
 
-	if (fpga_ver > 27)
+	if (0 && fpga_ver > 27)
 		card->using_dma = 1;
 	else {
 		/* Set RX empty flag for all ports */
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [GIT *] Solos PCI ADSL card update
  2009-03-17 19:23 ` David Miller
  2009-03-17 20:41   ` Stephen Hemminger
@ 2009-03-17 21:33   ` David Woodhouse
  1 sibling, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:33 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-atm-general, chas

On Tue, 2009-03-17 at 12:23 -0700, David Miller wrote:
> From: David Woodhouse <dwmw2@infradead.org>
> Date: Tue, 17 Mar 2009 17:19:30 +0000
> 
> > Please pull from git://git.infradead.org/~dwmw2/solos-2.6.git
> > 
> > This contains a bunch of updates to the Solos PCI driver (full patch
> > below for review):
> 
> So if I don't like patch 3 and want to discuss it as a unit,
> what do I do?  Pull the patch out of your GIT repo and
> start a thread to discuss it?

If you like :)

Since the complete patch isn't that large, I figured it was probably
easier to review that way. 

> Come on, post the whole series, please. :-/

Since the complete patch isn't that large, I figured it was probably
easier to review that way. I've posted them individually now.

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [GIT *] Solos PCI ADSL card update
  2009-03-17 20:41   ` Stephen Hemminger
@ 2009-03-17 21:36     ` David Woodhouse
  0 siblings, 0 replies; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 21:36 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev, linux-atm-general, chas

On Tue, 2009-03-17 at 13:41 -0700, Stephen Hemminger wrote:
> I regret ever adding sysfs for network devices when it gets used
> for configuration interfaces like this mess.

Yeah, I wasn't massively keen on that either.

You didn't speak up a while back when I asked for opinions on how best
to handle this. Feel free to do so now... 

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely
  2009-03-17 21:29 ` [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely David Woodhouse
@ 2009-03-17 22:44   ` Stephen Hemminger
  2009-03-17 22:49     ` David Woodhouse
  0 siblings, 1 reply; 38+ messages in thread
From: Stephen Hemminger @ 2009-03-17 22:44 UTC (permalink / raw)
  To: David Woodhouse; +Cc: netdev

On Tue, 17 Mar 2009 21:29:15 +0000
David Woodhouse <dwmw2@infradead.org> wrote:

> There are still a _lot_ of attributes, but for at least the basic ones
> we want to be able to get/set them from the kernel. Especially the ones
> we want to inform the ATM core about (link state, speed).
> 
> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
> ---

Since these are generic, please use some form of netlink for this
instead of sysfs.

Bonding was the first mistake (trying to use sysfs for a transactional API).
Pls don't repeat the mistake.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely
  2009-03-17 22:44   ` Stephen Hemminger
@ 2009-03-17 22:49     ` David Woodhouse
  2009-03-21 20:22       ` David Miller
  0 siblings, 1 reply; 38+ messages in thread
From: David Woodhouse @ 2009-03-17 22:49 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

On Tue, 2009-03-17 at 15:44 -0700, Stephen Hemminger wrote:
> Since these are generic, please use some form of netlink for this
> instead of sysfs.
> 
> Bonding was the first mistake (trying to use sysfs for a transactional
> API).
> Pls don't repeat the mistake.

It's not a transactional API.

The sysfs model actually fits the communication with the hardware almost
perfectly -- there are a bunch of named parameters, all of which can be
read and a few of which can be written to. A sysfs read or write
translates directly into a single exchange with the device's firmware.

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely
  2009-03-17 22:49     ` David Woodhouse
@ 2009-03-21 20:22       ` David Miller
  0 siblings, 0 replies; 38+ messages in thread
From: David Miller @ 2009-03-21 20:22 UTC (permalink / raw)
  To: dwmw2; +Cc: shemminger, netdev

From: David Woodhouse <dwmw2@infradead.org>
Date: Tue, 17 Mar 2009 22:49:32 +0000

> On Tue, 2009-03-17 at 15:44 -0700, Stephen Hemminger wrote:
> > Since these are generic, please use some form of netlink for this
> > instead of sysfs.
> > 
> > Bonding was the first mistake (trying to use sysfs for a transactional
> > API).
> > Pls don't repeat the mistake.
> 
> It's not a transactional API.
> 
> The sysfs model actually fits the communication with the hardware almost
> perfectly -- there are a bunch of named parameters, all of which can be
> read and a few of which can be written to. A sysfs read or write
> translates directly into a single exchange with the device's firmware.

Fair enough, I'll pull this into net-next-2.6

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2009-03-21 20:22 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-17 17:19 [GIT *] Solos PCI ADSL card update David Woodhouse
2009-03-17 19:23 ` David Miller
2009-03-17 20:41   ` Stephen Hemminger
2009-03-17 21:36     ` David Woodhouse
2009-03-17 21:33   ` David Woodhouse
2009-03-17 21:29 ` [PATCH 01/30] solos: Fix length header in FPGA transfers David Woodhouse
2009-03-17 21:29 ` [PATCH 02/30] solos: Slight debugging improvements David Woodhouse
2009-03-17 21:29 ` [PATCH 03/30] solos: FPGA and firmware update support David Woodhouse
2009-03-17 21:29 ` [PATCH 04/30] solos: Clean up firmware loading code David Woodhouse
2009-03-17 21:29 ` [PATCH 05/30] solos: Kill global 'opens' count David Woodhouse
2009-03-17 21:29 ` [PATCH 06/30] solos: Handle attribute show/store in kernel more sanely David Woodhouse
2009-03-17 22:44   ` Stephen Hemminger
2009-03-17 22:49     ` David Woodhouse
2009-03-21 20:22       ` David Miller
2009-03-17 21:29 ` [PATCH 08/30] solos: Handle new line status change packets, hook up to ATM layer info David Woodhouse
2009-03-17 21:29 ` [PATCH 07/30] solos: Add initial list of parameters David Woodhouse
2009-03-17 21:29 ` [PATCH 09/30] solos: Kill existing connections on link down event David Woodhouse
2009-03-17 21:29 ` [PATCH 10/30] solos: Reject non-AAL5 connections.... for now David Woodhouse
2009-03-17 21:29 ` [PATCH 11/30] solos: Add SNR and Attn to status packet, fix oops on load David Woodhouse
2009-03-17 21:29 ` [PATCH 12/30] solos: Fix under-allocation of skb size for get/set parameters David Woodhouse
2009-03-17 21:29 ` [PATCH 13/30] solos: Remove parameter group from sysfs on ATM dev deregister David Woodhouse
2009-03-17 21:29 ` [PATCH 14/30] solos: First attempt at DMA support David Woodhouse
2009-03-17 21:29 ` [PATCH 15/30] solos: Tidy up DMA handling a little. Still untested David Woodhouse
2009-03-17 21:29 ` [PATCH 16/30] solos: Tidy up tx_mask handling for ports which need TX David Woodhouse
2009-03-17 21:29 ` [PATCH 17/30] solos: Remove unused loopback debug stuff David Woodhouse
2009-03-17 21:29 ` [PATCH 18/30] solos: Remove IRQF_DISABLED, don't frob IRQ enable on the FPGA in solos_irq() David Woodhouse
2009-03-17 21:29 ` [PATCH 19/30] solos: Remove superfluous wait_queue_head_t from struct solos_param David Woodhouse
2009-03-17 21:29 ` [PATCH 20/30] solos: Fix various bugs in status packet handling David Woodhouse
2009-03-17 21:29 ` [PATCH 21/30] solos: Clean up handling of card->tx_mask a little David Woodhouse
2009-03-17 21:29 ` [PATCH 22/30] solos: Remove debugging, commented-out test code David Woodhouse
2009-03-17 21:29 ` [PATCH 23/30] solos: Add 'reset' module parameter to reset the DSL chips on load David Woodhouse
2009-03-17 21:29 ` [PATCH 24/30] solos: Tidy up status interrupt handling, cope with 'ERROR' status David Woodhouse
2009-03-17 21:29 ` [PATCH 26/30] solos: Set RX empty flag at startup only for !dma mode David Woodhouse
2009-03-17 21:29 ` [PATCH 25/30] solos: Don't clear config registers at startup David Woodhouse
2009-03-17 21:29 ` [PATCH 27/30] solos: Swap upstream/downstream rates in status packet, clean up some more David Woodhouse
2009-03-17 21:29 ` [PATCH 28/30] solos: Reset device on unload, free pending skbs David Woodhouse
2009-03-17 21:29 ` [PATCH 29/30] solos: Automatically determine number of ports David Woodhouse
2009-03-17 21:29 ` [PATCH 30/30] solos: Disable DMA until we have an FPGA update with it actually implemented David Woodhouse

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.