All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Woodhouse <dwmw2@infradead.org>
To: netdev@vger.kernel.org
Subject: [PATCH 04/30] solos: Clean up firmware loading code
Date: Tue, 17 Mar 2009 21:29:12 +0000	[thread overview]
Message-ID: <1237325352.27681.333.camel@macbook.infradead.org> (raw)
In-Reply-To: <1237310370.27681.314.camel@macbook.infradead.org>

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



  parent reply	other threads:[~2009-03-17 21:29 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` David Woodhouse [this message]
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 07/30] solos: Add initial list of parameters David Woodhouse
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 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 30/30] solos: Disable DMA until we have an FPGA update with it actually implemented David Woodhouse
2009-03-17 21:29 ` [PATCH 29/30] solos: Automatically determine number of ports David Woodhouse

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1237325352.27681.333.camel@macbook.infradead.org \
    --to=dwmw2@infradead.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.