Re: [PATCH] Intel IXP4xx network drivers v.2 - NPE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 8 May 2007, at 01:36, Krzysztof Halasa wrote:

Adds a driver for built-in IXP4xx Network Processor Engines.
This patch requires IXP4xx Queue Manager driver and the "fuses" patch.

Signed-off-by: Krzysztof Halasa <[email protected]>

[snip]

diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach- ixp4xx/ixp4xx_npe.c
new file mode 100644
index 0000000..4c77d8a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c

Already in mach-ixp4xx, so can just be called npe.c

@@ -0,0 +1,737 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * The code is based on publicly available information:
+ * - Intel IXP4xx Developer's Manual and other e-papers
+ * - Intel IXP400 Access Library Software (BSD license)
+ * - previous works by Christian Hohnstaedt <[email protected]>
+ *   Thanks, Christian.
+ */

[snip]

+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
+{
+	const struct firmware *fw_entry;
+
+	struct dl_block {
+		u32 type;
+		u32 offset;
+	} *blk;
+
+	struct dl_image {
+		u32 magic;
+		u32 id;
+		u32 size;
+		union {
+			u32 data[0];
+			struct dl_block blocks[0];
+		};
+	} *image;
+
+	struct dl_codeblock {
+		u32 npe_addr;
+		u32 size;
+		u32 data[0];
+	} *cb;
+
+	int i, j, err, data_size, instr_size, blocks, table_end;
+	u32 cmd;
+
+	if ((err = request_firmware(&fw_entry, name, dev)) != 0)
+		return err;
+
+	err = -EINVAL;
+	if (fw_entry->size < sizeof(struct dl_image)) {
+		print_npe(KERN_ERR, npe, "incomplete firmware file\n");
+		goto err;
+	}
+	image = (struct dl_image*)fw_entry->data;
+
+#if DEBUG_FW
+ print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes) \n",
+		  image->magic, image->id, image->size, image->size * 4);
+#endif
+
+	if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+		image->id = swab32(image->id);
+		image->size = swab32(image->size);
+	} else if (image->magic != FW_MAGIC) {
+		print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",
+			  image->magic);
+		goto err;
+	}
+	if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {
+		print_npe(KERN_ERR, npe,
+			  "inconsistent size of firmware file\n");
+		goto err;
+	}
+	if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+		print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");
+		goto err;
+	}
+	if (image->magic == swab32(FW_MAGIC))
+		for (i = 0; i < image->size; i++)
+			image->data[i] = swab32(image->data[i]);
+
+	if (!cpu_is_ixp46x() && ((image->id >> 28) & 0xF /* device ID */)) {
+		print_npe(KERN_INFO, npe, "IXP46x firmware ignored on "
+			  "IXP42x\n");
+		goto err;
+	}
+
+	if (npe_running(npe)) {
+		print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "
+			  "already running\n");
+		err = -EBUSY;
+		goto err;
+	}
+#if 0
+	npe_stop(npe);
+	npe_reset(npe);
+#endif

Debugging code? Can this go?

+	print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
+		  "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
+		  (image->id >> 8) & 0xFF, image->id & 0xFF);
+
+	if (!cpu_is_ixp46x()) {
+		if (!npe->id)
+			instr_size = NPE_A_42X_INSTR_SIZE;
+		else
+			instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+		data_size = NPE_42X_DATA_SIZE;
+	} else {
+		instr_size = NPE_46X_INSTR_SIZE;
+		data_size = NPE_46X_DATA_SIZE;
+	}
+
+	for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+	     blocks++)
+		if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+			break;
+	if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+		print_npe(KERN_INFO, npe, "firmware EOF block marker not "
+			  "found\n");
+		goto err;
+	}
+
+#if DEBUG_FW
+	print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);
+#endif
+
+ table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+	for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+		if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+		    || blk->offset < table_end) {
+			print_npe(KERN_INFO, npe, "invalid offset 0x%X of "
+				  "firmware block #%i\n", blk->offset, i);
+			goto err;
+		}
+
+		cb = (struct dl_codeblock*)&image->data[blk->offset];
+		if (blk->type == FW_BLOCK_TYPE_INSTR) {
+			if (cb->npe_addr + cb->size > instr_size)
+				goto too_big;
+			cmd = CMD_WR_INS_MEM;
+		} else if (blk->type == FW_BLOCK_TYPE_DATA) {
+			if (cb->npe_addr + cb->size > data_size)
+				goto too_big;
+			cmd = CMD_WR_DATA_MEM;
+		} else {
+			print_npe(KERN_INFO, npe, "invalid firmware block #%i "
+				  "type 0x%X\n", i, blk->type);
+			goto err;
+		}
+		if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+			print_npe(KERN_INFO, npe, "firmware block #%i doesn't "
+				  "fit in firmware image: type %c, start 0x%X,"
+				  " length 0x%X\n", i,
+				  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+				  cb->npe_addr, cb->size);
+			goto err;
+		}
+
+		for (j = 0; j < cb->size; j++)
+			npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+	}
+
+	npe_start(npe);
+	if (!npe_running(npe))
+		print_npe(KERN_ERR, npe, "unable to start\n");
+	release_firmware(fw_entry);
+	return 0;
+
+too_big:
+	print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "
+		  "memory: type %c, start 0x%X, length 0x%X\n", i,
+		  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+		  cb->npe_addr, cb->size);
+err:
+	release_firmware(fw_entry);
+	return err;
+}

[snip]

+module_init(npe_init_module);
+module_exit(npe_cleanup_module);
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_LICENSE("GPL v2");
+
+EXPORT_SYMBOL(npe_names);
+EXPORT_SYMBOL(npe_running);
+EXPORT_SYMBOL(npe_request);
+EXPORT_SYMBOL(npe_release);
+EXPORT_SYMBOL(npe_load_firmware);
+EXPORT_SYMBOL(npe_send_message);
+EXPORT_SYMBOL(npe_recv_message);
+EXPORT_SYMBOL(npe_send_recv_message);
diff --git a/include/asm-arm/arch-ixp4xx/npe.h b/include/asm-arm/ arch-ixp4xx/npe.h
new file mode 100644
index 0000000..fd20bf5
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/npe.h
@@ -0,0 +1,41 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+extern const char *npe_names[];
+
+struct npe_regs {
+	u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+	u32 action_points[4];
+	u32 watchpoint_fifo, watch_count;
+	u32 profile_count;
+	u32 messaging_status, messaging_control;
+	u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+	struct resource *mem_res;
+	struct npe_regs __iomem *regs;
+	u32 regs_phys;
+	int id;
+	int valid;
+};
+
+
+static inline const char *npe_name(struct npe *npe)
+{
+	return npe_names[npe->id];
+}
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what); +int npe_load_firmware(struct npe *npe, const char *name, struct device *dev);
+struct npe *npe_request(int id);
+void npe_release(struct npe *npe);
+
+#endif /* __IXP4XX_NPE_H */

It may be a matter of taste, but could some of the many definitions at the top of ixp4xx_npe.c go in the header file here?

Michael-Luke

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux