summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorAlexander D'hoore <dhoore.alexander@gmail.com>2017-12-15 15:37:58 +0100
committerDimitri Staessens <dimitri.staessens@ugent.be>2017-12-15 15:37:58 +0100
commitd1a1059d748955ed93a8e87c437c7eae1258293c (patch)
tree9137bc921db74bb3797b8b0f05e7a69022412522 /linux
parent8f258e469b1acea8e3ccf1485779e1db0bf5f772 (diff)
downloadraptor-d1a1059d748955ed93a8e87c437c7eae1258293c.tar.gz
raptor-d1a1059d748955ed93a8e87c437c7eae1258293c.zip
Add the linux device driver and netfpga files
This adds the device driver and netfpga files from the master thesis (in Dutch) "Implementatie van de Recursive Internet Architecture op een FPGA platform" by Alexander D'hoore.
Diffstat (limited to 'linux')
-rw-r--r--linux/Makefile7
-rw-r--r--linux/phy_conf.h728
-rw-r--r--linux/raptor.c940
3 files changed, 1675 insertions, 0 deletions
diff --git a/linux/Makefile b/linux/Makefile
new file mode 100644
index 0000000..9c7b2b9
--- /dev/null
+++ b/linux/Makefile
@@ -0,0 +1,7 @@
+obj-m += raptor.o
+
+all:
+ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
diff --git a/linux/phy_conf.h b/linux/phy_conf.h
new file mode 100644
index 0000000..71997ed
--- /dev/null
+++ b/linux/phy_conf.h
@@ -0,0 +1,728 @@
+
+#ifndef _PHY_CONF_H
+#define _PHY_CONF_H
+
+//#include "nf10driver.h"
+
+#define MDIO_BASE_ADDR 0x7a000000ULL // Check the Xilinx XPS Address Space if the hw changed
+
+#define PMA_MDIO_DEVICE_ADDRESS 1
+#define PCS_MDIO_DEVICE_ADDRESS 3
+#define PHY_XS_MDIO_DEVICE_ADDRESS 4
+
+#define PMA_CTL_REGISTER_ADDRESS 0x0
+#define PMA_STATUS_REGISTER_ADDRESS 0x1
+#define PMA_RESET_REGISTER_VALUE 0x8000
+#define PMA_SYS_LOOPBACK_REGISTER_VALUE 0x1
+#define PMA_RCV_SIG_DETECTED_ADDRESS 0xa
+
+#define PCS_STATUS_REGISTER_ADDRESS 0x1
+#define PHY_XS_STATUS_REGISTER_ADDRESS 0x1
+
+#define AEL_MICRO_CONTROLLER_CTL_ADDRESS 0xc04a
+
+#define AEL_I2C_CTRL 0xc30a
+#define AEL_I2C_DATA 0xc30b
+#define AEL_I2C_STAT 0xc30c
+
+#define XEL_MDIOCNTR_OFFSET 0x07F0 //< MDIO Control
+#define XEL_MDIOCNTR_STATUS_MASK 0x00000001 //< MDIO transfer in
+#define XEL_MDIO_ADDRESS_SHIFT 0x5 /**< PHY Address shift*/
+#define XEL_MDIO_ADDRESS_MASK 0x00003E0 /**< PHY Address mask */
+#define XEL_MDIOADDR_OFFSET 0x07E4 // < MDIO Address offset
+#define XEL_MDIOWR_OFFSET 0x07E8 //< MDIO write data
+#define XEL_MDIOCNTR_ENABLE_MASK 0x00000008 /**< MDIO Enable */
+#define XEL_MDIORD_OFFSET 0x07EC //< MDIO read data
+#define XEL_MDIO_OP_45_ADDRESS 0x00000000 /**< PHY address access */
+#define XEL_MDIO_OP_45_WRITE 0x00000400 /**< PHY write access */
+#define XEL_MDIO_OP_45_READ_INC 0x00000800 /**< PHY read inc access */
+#define XEL_MDIO_OP_45_READ 0x00000C00 /**< PHY read access */
+#define XEL_MDIO_CLAUSE_45 0x00001000 /**< PHY Clause type access */
+
+/* PHY module I2C device address */
+#define MODULE_DEV_ADDR 0xa0
+#define SFF_DEV_ADDR 0xa2
+
+enum {
+ MODE_TWINAX,
+ MODE_SR,
+ MODE_LR, // Not supported
+ MODE_LRM // Not supported
+};
+
+const uint16_t regs0[] = {
+ 0xc220, 0x711C
+ };
+
+const uint16_t regs1_1g[] = {
+ 0xc220, 0x744C
+ };
+
+// software reset and magic registers
+const uint16_t reset[] = {
+ 0x0000, 0xa040,
+ 0xc001, 0x0428,
+ 0xc017, 0xfeb0,
+ 0xc013, 0xf341,
+ 0xc210, 0x8000,
+ 0xc210, 0x8100,
+ 0xc210, 0x8000,
+ 0xc210, 0x0000
+ };
+
+// unpause the microprocessor
+const uint16_t regs1[] = {
+ 0xca00, 0x0080,
+ 0xca12, 0x0000
+ };
+
+// main Twinax EDC program
+const uint16_t twinax_edc[] = {
+ 0xc04a, 0x5a00,
+ 0xcc00, 0x4009,
+ 0xcc01, 0x27ff,
+ 0xcc02, 0x300f,
+ 0xcc03, 0x40aa,
+ 0xcc04, 0x401c,
+ 0xcc05, 0x401e,
+ 0xcc06, 0x2ff4,
+ 0xcc07, 0x3cd4,
+ 0xcc08, 0x2035,
+ 0xcc09, 0x3145,
+ 0xcc0a, 0x6524,
+ 0xcc0b, 0x26a2,
+ 0xcc0c, 0x3012,
+ 0xcc0d, 0x1002,
+ 0xcc0e, 0x29c2,
+ 0xcc0f, 0x3002,
+ 0xcc10, 0x1002,
+ 0xcc11, 0x2072,
+ 0xcc12, 0x3012,
+ 0xcc13, 0x1002,
+ 0xcc14, 0x22cd,
+ 0xcc15, 0x301d,
+ 0xcc16, 0x2e52,
+ 0xcc17, 0x3012,
+ 0xcc18, 0x1002,
+ 0xcc19, 0x28e2,
+ 0xcc1a, 0x3002,
+ 0xcc1b, 0x1002,
+ 0xcc1c, 0x628f,
+ 0xcc1d, 0x2ac2,
+ 0xcc1e, 0x3012,
+ 0xcc1f, 0x1002,
+ 0xcc20, 0x5553,
+ 0xcc21, 0x2ae2,
+ 0xcc22, 0x3002,
+ 0xcc23, 0x1302,
+ 0xcc24, 0x401e,
+ 0xcc25, 0x2be2,
+ 0xcc26, 0x3012,
+ 0xcc27, 0x1002,
+ 0xcc28, 0x2da2,
+ 0xcc29, 0x3012,
+ 0xcc2a, 0x1002,
+ 0xcc2b, 0x2ba2,
+ 0xcc2c, 0x3002,
+ 0xcc2d, 0x1002,
+ 0xcc2e, 0x5ee3,
+ 0xcc2f, 0x305,
+ 0xcc30, 0x400e,
+ 0xcc31, 0x2bc2,
+ 0xcc32, 0x3002,
+ 0xcc33, 0x1002,
+ 0xcc34, 0x2b82,
+ 0xcc35, 0x3012,
+ 0xcc36, 0x1002,
+ 0xcc37, 0x5663,
+ 0xcc38, 0x302,
+ 0xcc39, 0x401e,
+ 0xcc3a, 0x6f72,
+ 0xcc3b, 0x1002,
+ 0xcc3c, 0x628f,
+ 0xcc3d, 0x2be2,
+ 0xcc3e, 0x3012,
+ 0xcc3f, 0x1002,
+ 0xcc40, 0x22cd,
+ 0xcc41, 0x301d,
+ 0xcc42, 0x2e52,
+ 0xcc43, 0x3012,
+ 0xcc44, 0x1002,
+ 0xcc45, 0x2522,
+ 0xcc46, 0x3012,
+ 0xcc47, 0x1002,
+ 0xcc48, 0x2da2,
+ 0xcc49, 0x3012,
+ 0xcc4a, 0x1002,
+ 0xcc4b, 0x2ca2,
+ 0xcc4c, 0x3012,
+ 0xcc4d, 0x1002,
+ 0xcc4e, 0x2fa4,
+ 0xcc4f, 0x3cd4,
+ 0xcc50, 0x6624,
+ 0xcc51, 0x410b,
+ 0xcc52, 0x56b3,
+ 0xcc53, 0x3c4,
+ 0xcc54, 0x2fb2,
+ 0xcc55, 0x3002,
+ 0xcc56, 0x1002,
+ 0xcc57, 0x220b,
+ 0xcc58, 0x303b,
+ 0xcc59, 0x56b3,
+ 0xcc5a, 0x3c3,
+ 0xcc5b, 0x866b,
+ 0xcc5c, 0x400c,
+ 0xcc5d, 0x23a2,
+ 0xcc5e, 0x3012,
+ 0xcc5f, 0x1002,
+ 0xcc60, 0x2da2,
+ 0xcc61, 0x3012,
+ 0xcc62, 0x1002,
+ 0xcc63, 0x2ca2,
+ 0xcc64, 0x3012,
+ 0xcc65, 0x1002,
+ 0xcc66, 0x2fb4,
+ 0xcc67, 0x3cd4,
+ 0xcc68, 0x6624,
+ 0xcc69, 0x56b3,
+ 0xcc6a, 0x3c3,
+ 0xcc6b, 0x866b,
+ 0xcc6c, 0x401c,
+ 0xcc6d, 0x2205,
+ 0xcc6e, 0x3035,
+ 0xcc6f, 0x5b53,
+ 0xcc70, 0x2c52,
+ 0xcc71, 0x3002,
+ 0xcc72, 0x13c2,
+ 0xcc73, 0x5cc3,
+ 0xcc74, 0x317,
+ 0xcc75, 0x2522,
+ 0xcc76, 0x3012,
+ 0xcc77, 0x1002,
+ 0xcc78, 0x2da2,
+ 0xcc79, 0x3012,
+ 0xcc7a, 0x1002,
+ 0xcc7b, 0x2b82,
+ 0xcc7c, 0x3012,
+ 0xcc7d, 0x1002,
+ 0xcc7e, 0x5663,
+ 0xcc7f, 0x303,
+ 0xcc80, 0x401e,
+ 0xcc81, 0x004,
+ 0xcc82, 0x2c42,
+ 0xcc83, 0x3012,
+ 0xcc84, 0x1002,
+ 0xcc85, 0x6f72,
+ 0xcc86, 0x1002,
+ 0xcc87, 0x628f,
+ 0xcc88, 0x2304,
+ 0xcc89, 0x3c84,
+ 0xcc8a, 0x6436,
+ 0xcc8b, 0xdff4,
+ 0xcc8c, 0x6436,
+ 0xcc8d, 0x2ff5,
+ 0xcc8e, 0x3005,
+ 0xcc8f, 0x8656,
+ 0xcc90, 0xdfba,
+ 0xcc91, 0x56a3,
+ 0xcc92, 0xd05a,
+ 0xcc93, 0x21c2,
+ 0xcc94, 0x3012,
+ 0xcc95, 0x1392,
+ 0xcc96, 0xd05a,
+ 0xcc97, 0x56a3,
+ 0xcc98, 0xdfba,
+ 0xcc99, 0x383,
+ 0xcc9a, 0x6f72,
+ 0xcc9b, 0x1002,
+ 0xcc9c, 0x28c5,
+ 0xcc9d, 0x3005,
+ 0xcc9e, 0x4178,
+ 0xcc9f, 0x5653,
+ 0xcca0, 0x384,
+ 0xcca1, 0x22b2,
+ 0xcca2, 0x3012,
+ 0xcca3, 0x1002,
+ 0xcca4, 0x2be5,
+ 0xcca5, 0x3005,
+ 0xcca6, 0x41e8,
+ 0xcca7, 0x5653,
+ 0xcca8, 0x382,
+ 0xcca9, 0x002,
+ 0xccaa, 0x4258,
+ 0xccab, 0x2474,
+ 0xccac, 0x3c84,
+ 0xccad, 0x6437,
+ 0xccae, 0xdff4,
+ 0xccaf, 0x6437,
+ 0xccb0, 0x2ff5,
+ 0xccb1, 0x3c05,
+ 0xccb2, 0x8757,
+ 0xccb3, 0xb888,
+ 0xccb4, 0x9787,
+ 0xccb5, 0xdff4,
+ 0xccb6, 0x6724,
+ 0xccb7, 0x866a,
+ 0xccb8, 0x6f72,
+ 0xccb9, 0x1002,
+ 0xccba, 0x2d01,
+ 0xccbb, 0x3011,
+ 0xccbc, 0x1001,
+ 0xccbd, 0xc620,
+ 0xccbe, 0x14e5,
+ 0xccbf, 0xc621,
+ 0xccc0, 0xc53d,
+ 0xccc1, 0xc622,
+ 0xccc2, 0x3cbe,
+ 0xccc3, 0xc623,
+ 0xccc4, 0x4452,
+ 0xccc5, 0xc624,
+ 0xccc6, 0xc5c5,
+ 0xccc7, 0xc625,
+ 0xccc8, 0xe01e,
+ 0xccc9, 0xc627,
+ 0xccca, 0x000,
+ 0xcccb, 0xc628,
+ 0xcccc, 0x000,
+ 0xcccd, 0xc62b,
+ 0xccce, 0x000,
+ 0xcccf, 0xc62c,
+ 0xccd0, 0x000,
+ 0xccd1, 0x000,
+ 0xccd2, 0x2d01,
+ 0xccd3, 0x3011,
+ 0xccd4, 0x1001,
+ 0xccd5, 0xc620,
+ 0xccd6, 0x000,
+ 0xccd7, 0xc621,
+ 0xccd8, 0x000,
+ 0xccd9, 0xc622,
+ 0xccda, 0x0ce,
+ 0xccdb, 0xc623,
+ 0xccdc, 0x07f,
+ 0xccdd, 0xc624,
+ 0xccde, 0x032,
+ 0xccdf, 0xc625,
+ 0xcce0, 0x000,
+ 0xcce1, 0xc627,
+ 0xcce2, 0x000,
+ 0xcce3, 0xc628,
+ 0xcce4, 0x000,
+ 0xcce5, 0xc62b,
+ 0xcce6, 0x000,
+ 0xcce7, 0xc62c,
+ 0xcce8, 0x000,
+ 0xcce9, 0x000,
+ 0xccea, 0x2d01,
+ 0xcceb, 0x3011,
+ 0xccec, 0x1001,
+ 0xcced, 0xc502,
+ 0xccee, 0x609f,
+ 0xccef, 0xc600,
+ 0xccf0, 0x2a6e,
+ 0xccf1, 0xc601,
+ 0xccf2, 0x2a2c,
+ 0xccf3, 0xc60c,
+ 0xccf4, 0x5400,
+ 0xccf5, 0xc710,
+ 0xccf6, 0x700,
+ 0xccf7, 0xc718,
+ 0xccf8, 0x700,
+ 0xccf9, 0xc720,
+ 0xccfa, 0x4700,
+ 0xccfb, 0xc728,
+ 0xccfc, 0x700,
+ 0xccfd, 0xc729,
+ 0xccfe, 0x1207,
+ 0xccff, 0xc801,
+ 0xcd00, 0x7f50,
+ 0xcd01, 0xc802,
+ 0xcd02, 0x7760,
+ 0xcd03, 0xc803,
+ 0xcd04, 0x7fce,
+ 0xcd05, 0xc804,
+ 0xcd06, 0x520e,
+ 0xcd07, 0xc805,
+ 0xcd08, 0x5c11,
+ 0xcd09, 0xc806,
+ 0xcd0a, 0x3c51,
+ 0xcd0b, 0xc807,
+ 0xcd0c, 0x4061,
+ 0xcd0d, 0xc808,
+ 0xcd0e, 0x49c1,
+ 0xcd0f, 0xc809,
+ 0xcd10, 0x3840,
+ 0xcd11, 0xc80a,
+ 0xcd12, 0x000,
+ 0xcd13, 0xc821,
+ 0xcd14, 0x002,
+ 0xcd15, 0xc822,
+ 0xcd16, 0x046,
+ 0xcd17, 0xc844,
+ 0xcd18, 0x182f,
+ 0xcd19, 0xc013,
+ 0xcd1a, 0xf341,
+ 0xcd1b, 0xc01a,
+ 0xcd1c, 0x446,
+ 0xcd1d, 0xc024,
+ 0xcd1e, 0x1000,
+ 0xcd1f, 0xc025,
+ 0xcd20, 0xa00,
+ 0xcd21, 0xc026,
+ 0xcd22, 0xc0c,
+ 0xcd23, 0xc027,
+ 0xcd24, 0xc0c,
+ 0xcd25, 0xc029,
+ 0xcd26, 0x0a0,
+ 0xcd27, 0xc030,
+ 0xcd28, 0xa00,
+ 0xcd29, 0xc03c,
+ 0xcd2a, 0x01c,
+ 0xcd2b, 0x000,
+ 0xcd2c, 0x2b84,
+ 0xcd2d, 0x3c74,
+ 0xcd2e, 0x6435,
+ 0xcd2f, 0xdff4,
+ 0xcd30, 0x6435,
+ 0xcd31, 0x2806,
+ 0xcd32, 0x3006,
+ 0xcd33, 0x8565,
+ 0xcd34, 0x2b24,
+ 0xcd35, 0x3c24,
+ 0xcd36, 0x6436,
+ 0xcd37, 0x1002,
+ 0xcd38, 0x2b24,
+ 0xcd39, 0x3c24,
+ 0xcd3a, 0x6436,
+ 0xcd3b, 0x4045,
+ 0xcd3c, 0x8656,
+ 0xcd3d, 0x1002,
+ 0xcd3e, 0x2807,
+ 0xcd3f, 0x31a7,
+ 0xcd40, 0x20c4,
+ 0xcd41, 0x3c24,
+ 0xcd42, 0x6724,
+ 0xcd43, 0x1002,
+ 0xcd44, 0x2807,
+ 0xcd45, 0x3187,
+ 0xcd46, 0x20c4,
+ 0xcd47, 0x3c24,
+ 0xcd48, 0x6724,
+ 0xcd49, 0x1002,
+ 0xcd4a, 0x2514,
+ 0xcd4b, 0x3c64,
+ 0xcd4c, 0x6436,
+ 0xcd4d, 0xdff4,
+ 0xcd4e, 0x6436,
+ 0xcd4f, 0x1002,
+ 0xcd50, 0x2806,
+ 0xcd51, 0x3cb6,
+ 0xcd52, 0xc161,
+ 0xcd53, 0x6134,
+ 0xcd54, 0x6135,
+ 0xcd55, 0x5443,
+ 0xcd56, 0x303,
+ 0xcd57, 0x6524,
+ 0xcd58, 0x00b,
+ 0xcd59, 0x1002,
+ 0xcd5a, 0xd019,
+ 0xcd5b, 0x2104,
+ 0xcd5c, 0x3c24,
+ 0xcd5d, 0x2105,
+ 0xcd5e, 0x3805,
+ 0xcd5f, 0x6524,
+ 0xcd60, 0xdff4,
+ 0xcd61, 0x4005,
+ 0xcd62, 0x6524,
+ 0xcd63, 0x2e8d,
+ 0xcd64, 0x303d,
+ 0xcd65, 0x5dd3,
+ 0xcd66, 0x306,
+ 0xcd67, 0x2ff7,
+ 0xcd68, 0x38f7,
+ 0xcd69, 0x60b7,
+ 0xcd6a, 0xdffd,
+ 0xcd6b, 0x00a,
+ 0xcd6c, 0x1002,
+ 0xcd6d, 0
+ };
+
+// main SR EDC program
+const uint16_t sr_edc[] = {
+ 0xc003, 0x181,
+ 0xc010, 0x448a,
+ 0xc04a, 0x5200,
+ 0xcc00, 0x2ff4,
+ 0xcc01, 0x3cd4,
+ 0xcc02, 0x2015,
+ 0xcc03, 0x3105,
+ 0xcc04, 0x6524,
+ 0xcc05, 0x27ff,
+ 0xcc06, 0x300f,
+ 0xcc07, 0x2c8b,
+ 0xcc08, 0x300b,
+ 0xcc09, 0x4009,
+ 0xcc0a, 0x400e,
+ 0xcc0b, 0x2f72,
+ 0xcc0c, 0x3002,
+ 0xcc0d, 0x1002,
+ 0xcc0e, 0x2172,
+ 0xcc0f, 0x3012,
+ 0xcc10, 0x1002,
+ 0xcc11, 0x25d2,
+ 0xcc12, 0x3012,
+ 0xcc13, 0x1002,
+ 0xcc14, 0xd01e,
+ 0xcc15, 0x27d2,
+ 0xcc16, 0x3012,
+ 0xcc17, 0x1002,
+ 0xcc18, 0x2004,
+ 0xcc19, 0x3c84,
+ 0xcc1a, 0x6436,
+ 0xcc1b, 0x2007,
+ 0xcc1c, 0x3f87,
+ 0xcc1d, 0x8676,
+ 0xcc1e, 0x40b7,
+ 0xcc1f, 0xa746,
+ 0xcc20, 0x4047,
+ 0xcc21, 0x5673,
+ 0xcc22, 0x2982,
+ 0xcc23, 0x3002,
+ 0xcc24, 0x13d2,
+ 0xcc25, 0x8bbd,
+ 0xcc26, 0x2862,
+ 0xcc27, 0x3012,
+ 0xcc28, 0x1002,
+ 0xcc29, 0x2092,
+ 0xcc2a, 0x3012,
+ 0xcc2b, 0x1002,
+ 0xcc2c, 0x5cc3,
+ 0xcc2d, 0x314,
+ 0xcc2e, 0x2942,
+ 0xcc2f, 0x3002,
+ 0xcc30, 0x1002,
+ 0xcc31, 0xd019,
+ 0xcc32, 0x2032,
+ 0xcc33, 0x3012,
+ 0xcc34, 0x1002,
+ 0xcc35, 0x2a04,
+ 0xcc36, 0x3c74,
+ 0xcc37, 0x6435,
+ 0xcc38, 0x2fa4,
+ 0xcc39, 0x3cd4,
+ 0xcc3a, 0x6624,
+ 0xcc3b, 0x5563,
+ 0xcc3c, 0x2d42,
+ 0xcc3d, 0x3002,
+ 0xcc3e, 0x13d2,
+ 0xcc3f, 0x464d,
+ 0xcc40, 0x2862,
+ 0xcc41, 0x3012,
+ 0xcc42, 0x1002,
+ 0xcc43, 0x2032,
+ 0xcc44, 0x3012,
+ 0xcc45, 0x1002,
+ 0xcc46, 0x2fb4,
+ 0xcc47, 0x3cd4,
+ 0xcc48, 0x6624,
+ 0xcc49, 0x5563,
+ 0xcc4a, 0x2d42,
+ 0xcc4b, 0x3002,
+ 0xcc4c, 0x13d2,
+ 0xcc4d, 0x2ed2,
+ 0xcc4e, 0x3002,
+ 0xcc4f, 0x1002,
+ 0xcc50, 0x2fd2,
+ 0xcc51, 0x3002,
+ 0xcc52, 0x1002,
+ 0xcc53, 0x004,
+ 0xcc54, 0x2942,
+ 0xcc55, 0x3002,
+ 0xcc56, 0x1002,
+ 0xcc57, 0x2092,
+ 0xcc58, 0x3012,
+ 0xcc59, 0x1002,
+ 0xcc5a, 0x5cc3,
+ 0xcc5b, 0x317,
+ 0xcc5c, 0x2f72,
+ 0xcc5d, 0x3002,
+ 0xcc5e, 0x1002,
+ 0xcc5f, 0x2942,
+ 0xcc60, 0x3002,
+ 0xcc61, 0x1002,
+ 0xcc62, 0x22cd,
+ 0xcc63, 0x301d,
+ 0xcc64, 0x2862,
+ 0xcc65, 0x3012,
+ 0xcc66, 0x1002,
+ 0xcc67, 0x2ed2,
+ 0xcc68, 0x3002,
+ 0xcc69, 0x1002,
+ 0xcc6a, 0x2d72,
+ 0xcc6b, 0x3002,
+ 0xcc6c, 0x1002,
+ 0xcc6d, 0x628f,
+ 0xcc6e, 0x2112,
+ 0xcc6f, 0x3012,
+ 0xcc70, 0x1002,
+ 0xcc71, 0x5aa3,
+ 0xcc72, 0x2dc2,
+ 0xcc73, 0x3002,
+ 0xcc74, 0x1312,
+ 0xcc75, 0x6f72,
+ 0xcc76, 0x1002,
+ 0xcc77, 0x2807,
+ 0xcc78, 0x31a7,
+ 0xcc79, 0x20c4,
+ 0xcc7a, 0x3c24,
+ 0xcc7b, 0x6724,
+ 0xcc7c, 0x1002,
+ 0xcc7d, 0x2807,
+ 0xcc7e, 0x3187,
+ 0xcc7f, 0x20c4,
+ 0xcc80, 0x3c24,
+ 0xcc81, 0x6724,
+ 0xcc82, 0x1002,
+ 0xcc83, 0x2514,
+ 0xcc84, 0x3c64,
+ 0xcc85, 0x6436,
+ 0xcc86, 0xdff4,
+ 0xcc87, 0x6436,
+ 0xcc88, 0x1002,
+ 0xcc89, 0x40a4,
+ 0xcc8a, 0x643c,
+ 0xcc8b, 0x4016,
+ 0xcc8c, 0x8c6c,
+ 0xcc8d, 0x2b24,
+ 0xcc8e, 0x3c24,
+ 0xcc8f, 0x6435,
+ 0xcc90, 0x1002,
+ 0xcc91, 0x2b24,
+ 0xcc92, 0x3c24,
+ 0xcc93, 0x643a,
+ 0xcc94, 0x4025,
+ 0xcc95, 0x8a5a,
+ 0xcc96, 0x1002,
+ 0xcc97, 0x2731,
+ 0xcc98, 0x3011,
+ 0xcc99, 0x1001,
+ 0xcc9a, 0xc7a0,
+ 0xcc9b, 0x100,
+ 0xcc9c, 0xc502,
+ 0xcc9d, 0x53ac,
+ 0xcc9e, 0xc503,
+ 0xcc9f, 0xd5d5,
+ 0xcca0, 0xc600,
+ 0xcca1, 0x2a6d,
+ 0xcca2, 0xc601,
+ 0xcca3, 0x2a4c,
+ 0xcca4, 0xc602,
+ 0xcca5, 0x111,
+ 0xcca6, 0xc60c,
+ 0xcca7, 0x5900,
+ 0xcca8, 0xc710,
+ 0xcca9, 0x700,
+ 0xccaa, 0xc718,
+ 0xccab, 0x700,
+ 0xccac, 0xc720,
+ 0xccad, 0x4700,
+ 0xccae, 0xc801,
+ 0xccaf, 0x7f50,
+ 0xccb0, 0xc802,
+ 0xccb1, 0x7760,
+ 0xccb2, 0xc803,
+ 0xccb3, 0x7fce,
+ 0xccb4, 0xc804,
+ 0xccb5, 0x5700,
+ 0xccb6, 0xc805,
+ 0xccb7, 0x5f11,
+ 0xccb8, 0xc806,
+ 0xccb9, 0x4751,
+ 0xccba, 0xc807,
+ 0xccbb, 0x57e1,
+ 0xccbc, 0xc808,
+ 0xccbd, 0x2700,
+ 0xccbe, 0xc809,
+ 0xccbf, 0x000,
+ 0xccc0, 0xc821,
+ 0xccc1, 0x002,
+ 0xccc2, 0xc822,
+ 0xccc3, 0x014,
+ 0xccc4, 0xc832,
+ 0xccc5, 0x1186,
+ 0xccc6, 0xc847,
+ 0xccc7, 0x1e02,
+ 0xccc8, 0xc013,
+ 0xccc9, 0xf341,
+ 0xccca, 0xc01a,
+ 0xcccb, 0x446,
+ 0xcccc, 0xc024,
+ 0xcccd, 0x1000,
+ 0xccce, 0xc025,
+ 0xcccf, 0xa00,
+ 0xccd0, 0xc026,
+ 0xccd1, 0xc0c,
+ 0xccd2, 0xc027,
+ 0xccd3, 0xc0c,
+ 0xccd4, 0xc029,
+ 0xccd5, 0x0a0,
+ 0xccd6, 0xc030,
+ 0xccd7, 0xa00,
+ 0xccd8, 0xc03c,
+ 0xccd9, 0x01c,
+ 0xccda, 0xc005,
+ 0xccdb, 0x7a06,
+ 0xccdc, 0x000,
+ 0xccdd, 0x2731,
+ 0xccde, 0x3011,
+ 0xccdf, 0x1001,
+ 0xcce0, 0xc620,
+ 0xcce1, 0x000,
+ 0xcce2, 0xc621,
+ 0xcce3, 0x03f,
+ 0xcce4, 0xc622,
+ 0xcce5, 0x000,
+ 0xcce6, 0xc623,
+ 0xcce7, 0x000,
+ 0xcce8, 0xc624,
+ 0xcce9, 0x000,
+ 0xccea, 0xc625,
+ 0xcceb, 0x000,
+ 0xccec, 0xc627,
+ 0xcced, 0x000,
+ 0xccee, 0xc628,
+ 0xccef, 0x000,
+ 0xccf0, 0xc62c,
+ 0xccf1, 0x000,
+ 0xccf2, 0x000,
+ 0xccf3, 0x2806,
+ 0xccf4, 0x3cb6,
+ 0xccf5, 0xc161,
+ 0xccf6, 0x6134,
+ 0xccf7, 0x6135,
+ 0xccf8, 0x5443,
+ 0xccf9, 0x303,
+ 0xccfa, 0x6524,
+ 0xccfb, 0x00b,
+ 0xccfc, 0x1002,
+ 0xccfd, 0x2104,
+ 0xccfe, 0x3c24,
+ 0xccff, 0x2105,
+ 0xcd00, 0x3805,
+ 0xcd01, 0x6524,
+ 0xcd02, 0xdff4,
+ 0xcd03, 0x4005,
+ 0xcd04, 0x6524,
+ 0xcd05, 0x1002,
+ 0xcd06, 0x5dd3,
+ 0xcd07, 0x306,
+ 0xcd08, 0x2ff7,
+ 0xcd09, 0x38f7,
+ 0xcd0a, 0x60b7,
+ 0xcd0b, 0xdffd,
+ 0xcd0c, 0x00a,
+ 0xcd0d, 0x1002,
+ 0xcd0e, 0
+ };
+
+#endif
diff --git a/linux/raptor.c b/linux/raptor.c
new file mode 100644
index 0000000..cb28c44
--- /dev/null
+++ b/linux/raptor.c
@@ -0,0 +1,940 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2017
+ *
+ * Raptor device driver
+ *
+ * Alexander D'hoore <dhoore.alexander@gmail.com>
+ * Dimitri Staessens <dimitri.staessens@ugent.be>
+ * Sander Vrijders <sander.vrijders@ugent.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+
+#include "phy_conf.h"
+
+MODULE_LICENSE("GPL");
+
+#define RAPTOR_VENDOR_ID 0x10EE
+#define RAPTOR_DEVICE_ID 0xAD02
+#define RAPTOR_BAR 0
+
+#define BAR_MDIO 30
+
+#define CMD_STATUS 0
+#define CMD_SEND 1
+#define CMD_RECV 2
+#define CMD_MDIO 3
+
+#define IOCTL_SEND 0xAD420000
+#define IOCTL_RECV 0xAD430000
+#define IOCTL_SEND_DONE 0xAD440000
+#define IOCTL_RECV_DONE 0xAD450000
+#define IOCTL_RECV_NEED 0xAD460000
+#define IOCTL_DEBUG 0xAD470000
+
+#define BUFF_COUNT 16
+
+#define BUFF_EMPTY 0
+#define BUFF_ADDR 1
+#define BUFF_DATA 2
+#define BUFF_FULL 3
+
+#define PACKET_COUNT 1000
+
+struct packet;
+
+struct packet {
+ uint64_t u_addr;
+ uint16_t length;
+ struct page* page;
+ dma_addr_t dma_addr;
+ struct packet* next;
+};
+
+struct queue {
+ struct packet* first;
+ struct packet* last;
+ uint64_t count;
+};
+
+struct raptor {
+ dev_t base;
+ struct class * class;
+
+ dev_t dev;
+ struct device * device;
+ struct cdev cdev;
+
+ uint64_t *bar;
+ struct pci_dev *pdev;
+
+ bool interrupt;
+
+ struct queue send_queue;
+ struct queue recv_queue;
+ struct queue send_done_queue;
+ struct queue recv_done_queue;
+ struct queue send_free_queue;
+ struct queue recv_free_queue;
+
+ struct packet* send_packets;
+ struct packet* recv_packets;
+
+ uint64_t recv_need;
+
+ spinlock_t lock;
+ wait_queue_head_t wait;
+
+ struct task_struct* kthread;
+
+ uint64_t int_count;
+ uint64_t send_busy;
+ uint64_t recv_busy;
+};
+
+struct raptor raptor;
+
+// -------------------------------------------
+
+static void queue_push(struct queue* queue, struct packet* packet)
+{
+ spin_lock_irq(&raptor.lock);
+
+ if (queue->count == 0) {
+ queue->first = packet;
+ queue->last = packet;
+ }
+ else {
+ queue->last->next = packet;
+ queue->last = packet;
+ }
+ queue->count++;
+
+ spin_unlock_irq(&raptor.lock);
+ wake_up(&raptor.wait);
+}
+
+static struct packet* queue_pop(struct queue* queue, bool block)
+{
+ struct packet* packet;
+
+ spin_lock_irq(&raptor.lock);
+
+ if (block) {
+ if (wait_event_interruptible_lock_irq_timeout(
+ raptor.wait, queue->count > 0, raptor.lock, HZ) <= 0) {
+
+ spin_unlock_irq(&raptor.lock);
+ return NULL;
+ }
+ }
+ else {
+ if (queue->count == 0) {
+ spin_unlock_irq(&raptor.lock);
+ return NULL;
+ }
+ }
+
+ packet = queue->first;
+ queue->first = packet->next;
+ queue->count--;
+
+ spin_unlock_irq(&raptor.lock);
+ wake_up(&raptor.wait);
+ return packet;
+}
+
+// -------------------------------------------
+
+uint64_t raptor_read(uint64_t offset)
+{
+ return raptor.bar[offset];
+}
+
+void raptor_write(uint64_t offset, uint64_t data)
+{
+ raptor.bar[offset] = data;
+}
+
+uint64_t endian64(uint64_t data)
+{
+ uint64_t byte0 = (data & 0x00000000000000FF) << 7*8;
+ uint64_t byte1 = (data & 0x000000000000FF00) << 5*8;
+ uint64_t byte2 = (data & 0x0000000000FF0000) << 3*8;
+ uint64_t byte3 = (data & 0x00000000FF000000) << 1*8;
+ uint64_t byte4 = (data & 0x000000FF00000000) >> 1*8;
+ uint64_t byte5 = (data & 0x0000FF0000000000) >> 3*8;
+ uint64_t byte6 = (data & 0x00FF000000000000) >> 5*8;
+ uint64_t byte7 = (data & 0xFF00000000000000) >> 7*8;
+
+ return byte0 | byte1 | byte2 | byte3 | byte4 | byte5 | byte6 | byte7;
+}
+
+static irqreturn_t raptor_interrupt(int irq, void *dev_id)
+{
+ spin_lock(&raptor.lock);
+ raptor.interrupt = true;
+ spin_unlock(&raptor.lock);
+ wake_up(&raptor.wait);
+
+ return IRQ_HANDLED;
+}
+
+void mdio_raw(unsigned operation, unsigned phy_addr, unsigned dev_addr, unsigned data)
+{
+ unsigned command = (operation << 26) | (phy_addr << 21) | (dev_addr << 16) | (data & 0xFFFF);
+
+ raptor_write(CMD_MDIO, endian64((uint64_t)command));
+ msleep(1);
+}
+
+void mdio_write(unsigned phy_addr, unsigned dev_addr, unsigned data_addr, unsigned data)
+{
+ mdio_raw(0, phy_addr, dev_addr, data_addr);
+ mdio_raw(1, phy_addr, dev_addr, data);
+}
+
+unsigned mdio_read(unsigned phy_addr, unsigned dev_addr, unsigned data_addr)
+{
+ mdio_raw(0, phy_addr, dev_addr, data_addr);
+ mdio_raw(3, phy_addr, dev_addr, 0);
+
+ return (unsigned)endian64(raptor_read(BAR_MDIO));
+}
+
+int mdio_i2c_read(uint32_t phy_addr, uint16_t dev_addr, uint16_t word_addr, uint16_t * data)
+{
+ uint16_t stat;
+ int i;
+
+ mdio_write(phy_addr, 1, AEL_I2C_CTRL, (dev_addr << 8) | (1 << 8) | word_addr);
+
+ for (i = 0; i < 20; i++) {
+ msleep(2);
+ stat = mdio_read(phy_addr, 1, AEL_I2C_STAT);
+
+ if ((stat & 3) == 1){
+ stat = mdio_read(phy_addr, 1, AEL_I2C_DATA);
+
+ *data = stat >> 8;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void mdio_initialize(uint32_t phy_addr, int mode)
+{
+ int size, i;
+
+ // Step 1
+ size = sizeof(reset) / sizeof(uint16_t);
+
+ for(i = 0; i < size; i += 2) {
+ mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, reset[i], reset[i+1]);
+ }
+
+ msleep(5);
+
+ // Step 2
+ if (mode == MODE_SR) {
+ size = sizeof(sr_edc) / sizeof(uint16_t);
+
+ for(i = 0; i < size; i += 2) {
+ mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, sr_edc[i], sr_edc[i+1]);
+ }
+ }
+ else if (mode == MODE_TWINAX) {
+ size = sizeof(twinax_edc) / sizeof(uint16_t);
+
+ for(i = 0; i < size; i += 2) {
+ mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, twinax_edc[i], twinax_edc[i+1]);
+ }
+ }
+
+ // Step 3
+ size = sizeof(regs1) / sizeof(uint16_t);
+ for(i = 0; i < size; i+=2) {
+ mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, regs1[i], regs1[i+1]);
+ }
+
+ msleep(5);
+}
+
+int phy_configuration(void)
+{
+ int port, dev;
+ uint16_t value = 0;
+ char port_mode;
+
+ // check if we need initialization
+ value = mdio_read(2, PMA_MDIO_DEVICE_ADDRESS, AEL_MICRO_CONTROLLER_CTL_ADDRESS);
+
+ //printk(KERN_INFO "raptor: 0xc04a: %04x\n",value);
+ if (value & 0x8000) { // uC held in reset
+ printk(KERN_INFO "raptor: Programming the AEL2005 PHY chips...\n");
+
+ for (port = 0; port < 4; port++) {
+ if (port == 0) dev = 2;
+ else if (port == 1) dev = 1;
+ else if (port == 2) dev = 0;
+ else dev = 3;
+
+ value = 0;
+
+ // check if we have a 10GBASE-SR cable
+ mdio_i2c_read(dev, MODULE_DEV_ADDR, 0x3, &value);
+
+ if((value >> 4) == 1) {
+ port_mode = MODE_SR;
+ }
+ else {
+ port_mode = MODE_TWINAX;
+ }
+
+ printk(KERN_INFO "raptor: Programming PHY %d...\n", port);
+
+ mdio_initialize(dev, port_mode);
+ }
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static void read_debug(void)
+{
+ uint64_t status;
+ uint64_t address;
+ uint64_t data;
+ uint64_t cmd;
+ uint64_t buff;
+ uint64_t length;
+ uint64_t cmpl_count;
+ uint64_t cmpl_data;
+ uint64_t cmpl_tag;
+ uint64_t cmpl_state;
+ uint64_t write_count;
+ uint64_t write_length;
+ uint64_t write_addr;
+ uint64_t write_data;
+ uint64_t accept_count;
+ uint64_t done_count;
+
+ status = endian64(raptor_read(0));
+ address = endian64(raptor_read(1));
+ data = endian64(raptor_read(2));
+ cmd = endian64(raptor_read(3));
+ buff = endian64(raptor_read(4));
+ length = endian64(raptor_read(5));
+ cmpl_count = endian64(raptor_read(10));
+ cmpl_data = endian64(raptor_read(11));
+ cmpl_tag = endian64(raptor_read(12));
+ cmpl_state = endian64(raptor_read(13));
+
+ write_count = endian64(raptor_read(20));
+ write_length = endian64(raptor_read(21));
+ write_addr = endian64(raptor_read(22));
+ write_data = endian64(raptor_read(23));
+ accept_count = endian64(raptor_read(24));
+ done_count = endian64(raptor_read(25));
+
+ printk(KERN_INFO "raptor: read_debug:\n");
+ printk(KERN_INFO "raptor: status = 0x%llx.\n", status);
+ printk(KERN_INFO "raptor: address = 0x%llx.\n", address);
+ printk(KERN_INFO "raptor: data = 0x%llx.\n", data);
+ printk(KERN_INFO "raptor: cmd = 0x%llx.\n", cmd);
+ printk(KERN_INFO "raptor: buff = 0x%llx.\n", buff);
+ printk(KERN_INFO "raptor: length = %llu.\n", length);
+ printk(KERN_INFO "raptor: cmpl_count = %llu.\n", cmpl_count);
+ printk(KERN_INFO "raptor: cmpl_data = 0x%llx.\n", cmpl_data);
+ printk(KERN_INFO "raptor: cmpl_tag = 0x%llx.\n", cmpl_tag);
+ printk(KERN_INFO "raptor: cmpl_state = 0x%llx.\n", cmpl_state);
+ printk(KERN_INFO "raptor: write_count = %llu.\n", write_count);
+ printk(KERN_INFO "raptor: write_length = %llu.\n", write_length);
+ printk(KERN_INFO "raptor: write_addr = 0x%llx.\n", write_addr);
+ printk(KERN_INFO "raptor: write_data = 0x%llx.\n", write_data);
+ printk(KERN_INFO "raptor: accept_count = %llu.\n", accept_count);
+ printk(KERN_INFO "raptor: done_count = %llu.\n", done_count);
+}
+
+#define get_send(status, i) ((status >> (i * 4 + 0)) & 0x3)
+#define get_recv(status, i) ((status >> (i * 4 + 2)) & 0x3)
+
+struct packet* send_packets[BUFF_COUNT];
+struct packet* recv_packets[BUFF_COUNT];
+uint8_t send_buff[BUFF_COUNT];
+uint8_t recv_buff[BUFF_COUNT];
+
+static int raptor_kthread(void* data)
+{
+ bool interrupt;
+ uint64_t status = 0;
+ uint8_t send_new;
+ uint8_t recv_new;
+ uint8_t send_old;
+ uint8_t recv_old;
+ uint64_t i;
+ bool send_full = false;
+ bool recv_full = false;
+ struct packet* packet;
+ struct device* dev = &raptor.pdev->dev;
+ uint64_t offset;
+ uint64_t rest;
+
+ printk(KERN_INFO "raptor_kthread: started\n");
+
+ memset(send_packets, 0, sizeof(send_packets));
+ memset(recv_packets, 0, sizeof(recv_packets));
+
+ raptor.interrupt = true;
+
+ while (true) {
+ spin_lock_irq(&raptor.lock);
+
+ if (wait_event_interruptible_lock_irq(
+ raptor.wait,
+ kthread_should_stop() ||
+ raptor.interrupt ||
+ (! send_full && raptor.send_queue.count > 0) ||
+ (! recv_full && raptor.recv_queue.count > 0),
+ raptor.lock) != 0) {
+
+ printk(KERN_ERR "raptor_kthread: wait_event failed\n");
+ spin_unlock_irq(&raptor.lock);
+ break;
+ }
+
+ interrupt = raptor.interrupt;
+ raptor.interrupt = false;
+ spin_unlock_irq(&raptor.lock);
+
+ if (kthread_should_stop())
+ break;
+
+ if (interrupt) {
+ // read status
+ // update done_queues
+ // incr recv_need
+ status = endian64(raptor_read(0));
+
+ raptor.int_count++;
+
+ for (i = 0; i < BUFF_COUNT; i++) {
+ send_new = get_send(status, i);
+ recv_new = get_recv(status, i);
+ send_old = send_buff[i];
+ recv_old = recv_buff[i];
+
+ if (send_new != BUFF_EMPTY)
+ raptor.send_busy++;
+ if (recv_new != BUFF_EMPTY)
+ raptor.recv_busy++;
+
+ if ((send_old == BUFF_ADDR || send_old == BUFF_DATA) &&
+ (send_new == BUFF_FULL || send_new == BUFF_EMPTY) &&
+ send_packets[i] != NULL) {
+
+ packet = send_packets[i];
+ offset = packet->u_addr & (~PAGE_MASK);
+ rest = PAGE_SIZE - offset;
+
+ dma_unmap_page(dev, packet->dma_addr, rest, DMA_TO_DEVICE);
+ queue_push(&raptor.send_done_queue, packet);
+ send_packets[i] = NULL;
+ }
+ if ((recv_old == BUFF_ADDR || recv_old == BUFF_DATA) &&
+ (recv_new == BUFF_FULL || recv_new == BUFF_EMPTY) &&
+ recv_packets[i] != NULL) {
+
+ packet = recv_packets[i];
+ offset = packet->u_addr & (~PAGE_MASK);
+ rest = PAGE_SIZE - offset;
+
+ dma_unmap_page(dev, packet->dma_addr, rest, DMA_FROM_DEVICE);
+ queue_push(&raptor.recv_done_queue, packet);
+ recv_packets[i] = NULL;
+ }
+ if (recv_old != BUFF_FULL && recv_new == BUFF_FULL) {
+ spin_lock_irq(&raptor.lock);
+ raptor.recv_need++;
+ spin_unlock_irq(&raptor.lock);
+ wake_up(&raptor.wait);
+ }
+
+ send_buff[i] = send_new;
+ recv_buff[i] = recv_new;
+ }
+ }
+
+ // handle send_queue
+ send_full = true;
+
+ for (i = 0; i < BUFF_COUNT; i++) {
+ if (send_buff[i] == BUFF_EMPTY && send_packets[i] == NULL) {
+
+ packet = queue_pop(&raptor.send_queue, false);
+
+ if (packet == NULL) {
+ send_full = false;
+ break;
+ }
+
+ // map page to dma_addr
+ // write that to hardware
+
+ offset = packet->u_addr & (~PAGE_MASK);
+ rest = PAGE_SIZE - offset;
+
+ packet->dma_addr = dma_map_page(dev, packet->page, offset, rest, DMA_TO_DEVICE);
+
+ raptor_write(CMD_SEND | (i << 2) | (packet->length << 7), endian64(packet->dma_addr));
+
+ send_buff[i] = BUFF_ADDR;
+ send_packets[i] = packet;
+ }
+ }
+
+ // handle recv_queue
+ recv_full = true;
+
+ for (i = 0; i < BUFF_COUNT; i++) {
+ if (recv_buff[i] == BUFF_FULL && recv_packets[i] == NULL) {
+
+ packet = queue_pop(&raptor.recv_queue, false);
+
+ if (packet == NULL) {
+ recv_full = false;
+ break;
+ }
+
+ // map page to dma_addr
+ // write that to hardware
+
+ offset = packet->u_addr & (~PAGE_MASK);
+ rest = PAGE_SIZE - offset;
+
+ packet->dma_addr = dma_map_page(dev, packet->page, offset, rest, DMA_FROM_DEVICE);
+
+ raptor_write(CMD_RECV | (i << 2), endian64(packet->dma_addr));
+
+ recv_buff[i] = BUFF_ADDR;
+ recv_packets[i] = packet;
+ }
+ }
+ }
+
+ printk(KERN_INFO "raptor_kthread: stopped\n");
+ return 0;
+}
+
+static int pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ if (pci_enable_device(pdev) != 0)
+ goto error_no_cleanup;
+
+ if (pci_request_region(pdev, RAPTOR_BAR, "raptor") != 0)
+ goto error_disable_device;
+
+ if ((raptor.bar = pci_ioremap_bar(pdev, RAPTOR_BAR)) == NULL)
+ goto error_release_region;
+
+ if (pci_enable_msi(pdev) < 0)
+ goto error_iounmap;
+
+ if (request_irq(pdev->irq, raptor_interrupt, 0, "raptor", NULL) < 0)
+ goto error_disable_msi;
+
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) < 0)
+ goto error_free_irq;
+
+ if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)) < 0)
+ goto error_free_irq;
+
+ pci_set_master(pdev);
+ raptor.pdev = pdev;
+
+ phy_configuration();
+
+ read_debug();
+
+ raptor.kthread = kthread_run(raptor_kthread, NULL, "raptor_kthread");
+
+ if (IS_ERR(raptor.kthread))
+ goto error_clear_master;
+
+ printk(KERN_INFO "raptor: pci_probe succes\n");
+
+ return 0;
+
+error_clear_master:
+ pci_clear_master(pdev);
+error_free_irq:
+ free_irq(pdev->irq, NULL);
+error_disable_msi:
+ pci_disable_msi(pdev);
+error_iounmap:
+ iounmap(raptor.bar);
+error_release_region:
+ pci_release_region(pdev, 0);
+error_disable_device:
+ pci_disable_device(pdev);
+error_no_cleanup:
+ raptor.bar = NULL;
+ raptor.pdev = NULL;
+ printk(KERN_ALERT "raptor: pci_probe FAILED\n");
+ return -1;
+}
+
+static void pci_remove(struct pci_dev *pdev)
+{
+ printk(KERN_INFO "raptor: pci_remove started...\n");
+
+ (void)kthread_stop(raptor.kthread);
+
+ pci_clear_master(pdev);
+ free_irq(pdev->irq, NULL);
+ pci_disable_msi(pdev);
+ iounmap(raptor.bar);
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
+ raptor.bar = NULL;
+ raptor.pdev = NULL;
+
+ printk(KERN_INFO "raptor: pci_remove done\n");
+}
+
+static pci_ers_result_t pci_error_detected(struct pci_dev *pdev, enum pci_channel_state state)
+{
+ printk(KERN_ALERT "raptor: pcie error %d\n", state);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static int raptor_send(uint64_t count, uint64_t* u_addrs)
+{
+ uint64_t i;
+ uint64_t u_addr;
+ uint16_t bytes;
+ uint16_t length;
+ struct page* page;
+ struct packet* packet;
+
+ for (i = 0; i < count; i++) {
+ if (copy_from_user(&u_addr, &u_addrs[i], sizeof(u_addr)) != 0) {
+ printk(KERN_ERR "raptor_send: copy_from_user u_addr failed\n");
+ return i;
+ }
+
+ if (copy_from_user(&bytes, (void*)u_addr, sizeof(bytes)) != 0) {
+ printk(KERN_ERR "raptor_send: copy_from_user bytes failed\n");
+ return i;
+ }
+
+ if (get_user_pages_fast(u_addr, 1, false, &page) != 1) {
+ printk(KERN_ERR "raptor_send: get_user_pages_fast failed\n");
+ return i;
+ }
+
+ packet = queue_pop(&raptor.send_free_queue, true);
+
+ if (packet == NULL) {
+ printk(KERN_ERR "raptor_send: queue_pop send_free_queue failed\n");
+ put_page(page);
+ return i;
+ }
+
+ length = (bytes >> 3);
+
+ if (bytes & 0x7)
+ length += 1;
+
+ packet->u_addr = u_addr;
+ packet->length = length;
+ packet->page = page;
+
+ queue_push(&raptor.send_queue, packet);
+ }
+ return count;
+}
+
+static int raptor_recv(uint64_t count, uint64_t* u_addrs)
+{
+ uint64_t i;
+ uint64_t u_addr;
+ struct page* page;
+ struct packet* packet;
+
+ for (i = 0; i < count; i++) {
+ if (copy_from_user(&u_addr, &u_addrs[i], sizeof(u_addr)) != 0) {
+ printk(KERN_ERR "raptor_recv: copy_from_user u_addr failed\n");
+ return i;
+ }
+
+ if (get_user_pages_fast(u_addr, 1, true, &page) != 1) {
+ printk(KERN_ERR "raptor_recv: get_user_pages_fast failed\n");
+ return i;
+ }
+
+ packet = queue_pop(&raptor.recv_free_queue, true);
+
+ if (packet == NULL) {
+ printk(KERN_ERR "raptor_recv: queue_pop recv_free_queue failed\n");
+ put_page(page);
+ return i;
+ }
+
+ packet->u_addr = u_addr;
+ packet->page = page;
+
+ queue_push(&raptor.recv_queue, packet);
+ }
+ return count;
+}
+
+static int raptor_send_done(uint64_t count, uint64_t* u_addrs)
+{
+ uint64_t i;
+ struct packet* packet;
+
+ for (i = 0; i < count; i++) {
+ packet = queue_pop(&raptor.send_done_queue, i == 0);
+
+ if (packet == NULL)
+ return i;
+
+ put_page(packet->page);
+
+ if (copy_to_user(&u_addrs[i], &packet->u_addr, sizeof(packet->u_addr)) != 0) {
+ printk(KERN_ERR "raptor_send_done: copy_to_user u_addr failed\n");
+ return i;
+ }
+
+ queue_push(&raptor.send_free_queue, packet);
+ }
+ return count;
+}
+
+static int raptor_recv_done(uint64_t count, uint64_t* u_addrs)
+{
+ uint64_t i;
+ struct packet* packet;
+
+ for (i = 0; i < count; i++) {
+ packet = queue_pop(&raptor.recv_done_queue, i == 0);
+
+ if (packet == NULL)
+ return i;
+
+ put_page(packet->page);
+
+ if (copy_to_user(&u_addrs[i], &packet->u_addr, sizeof(packet->u_addr)) != 0) {
+ printk(KERN_ERR "raptor_recv_done: copy_to_user u_addr failed\n");
+ return i;
+ }
+
+ queue_push(&raptor.recv_free_queue, packet);
+ }
+ return count;
+}
+
+static int raptor_recv_need(uint64_t count)
+{
+ uint64_t ret;
+
+ spin_lock_irq(&raptor.lock);
+
+ if (wait_event_interruptible_lock_irq_timeout(
+ raptor.wait, raptor.recv_need > 0, raptor.lock, HZ) <= 0) {
+
+ spin_unlock_irq(&raptor.lock);
+ return -1;
+ }
+
+ if (raptor.recv_need > count) {
+ ret = count;
+ raptor.recv_need -= count;
+ }
+ else {
+ ret = raptor.recv_need;
+ raptor.recv_need = 0;
+ }
+
+ spin_unlock_irq(&raptor.lock);
+ return ret;
+}
+
+static int raptor_debug(uint64_t* u_array)
+{
+ if (copy_to_user(&u_array[0], &raptor.int_count, sizeof(uint64_t)) ||
+ copy_to_user(&u_array[1], &raptor.send_busy, sizeof(uint64_t)) ||
+ copy_to_user(&u_array[2], &raptor.recv_busy, sizeof(uint64_t))) {
+
+ printk(KERN_ERR "raptor_debug: copy_to_user failed\n");
+ return -1;
+ }
+
+ raptor.int_count = 0;
+ raptor.send_busy = 0;
+ raptor.recv_busy = 0;
+
+ return 0;
+}
+
+
+static long raptor_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
+{
+ uint64_t type = cmd & 0xFFFF0000;
+ uint64_t count = cmd & 0x0000FFFF;
+
+ if (raptor.bar == NULL) {
+ printk(KERN_ERR "raptor: no pcie device\n");
+ return -1;
+ }
+
+ switch (type) {
+ case IOCTL_SEND:
+ return raptor_send(count, (uint64_t*)arg);
+ case IOCTL_RECV:
+ return raptor_recv(count, (uint64_t*)arg);
+ case IOCTL_SEND_DONE:
+ return raptor_send_done(count, (uint64_t*)arg);
+ case IOCTL_RECV_DONE:
+ return raptor_recv_done(count, (uint64_t*)arg);
+ case IOCTL_RECV_NEED:
+ return raptor_recv_need(count);
+ case IOCTL_DEBUG:
+ return raptor_debug((uint64_t*)arg);
+ default:
+ printk(KERN_ERR "raptor: unknown ioctl\n");
+ return -1;
+ }
+}
+
+static struct pci_device_id pci_id_table[] = {
+ {PCI_DEVICE(RAPTOR_VENDOR_ID, RAPTOR_DEVICE_ID)},
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, pci_id_table);
+
+static struct pci_error_handlers pci_err_handlers = {
+ .error_detected = pci_error_detected
+};
+
+static struct pci_driver pci_driver = {
+ .name = "raptor",
+ .id_table = pci_id_table,
+ .probe = pci_probe,
+ .remove = pci_remove,
+ .err_handler = &pci_err_handlers
+};
+
+static struct file_operations raptor_fops = {
+ .unlocked_ioctl = raptor_ioctl,
+};
+
+int init_module(void)
+{
+ int i;
+
+ printk(KERN_INFO "raptor: inserting module...\n");
+
+ memset(&raptor, 0, sizeof(raptor));
+
+ spin_lock_init(&raptor.lock);
+ init_waitqueue_head(&raptor.wait);
+
+ raptor.send_packets = kmalloc(PACKET_COUNT * sizeof(struct packet), GFP_KERNEL);
+ raptor.recv_packets = kmalloc(PACKET_COUNT * sizeof(struct packet), GFP_KERNEL);
+
+ if (raptor.send_packets == NULL || raptor.recv_packets == NULL) {
+ printk(KERN_ERR "raptor: failed to allocate packets\n");
+ return -1;
+ }
+
+ for (i = 0; i < PACKET_COUNT; i++) {
+ queue_push(&raptor.send_free_queue, &raptor.send_packets[i]);
+ queue_push(&raptor.recv_free_queue, &raptor.recv_packets[i]);
+ }
+
+ if (alloc_chrdev_region(&raptor.base, 0, 1, "raptor") < 0) {
+ printk(KERN_ERR "raptor: alloc_chrdev_region failed\n");
+ return -1;
+ }
+
+ raptor.class = class_create(THIS_MODULE, "raptor");
+
+ if (IS_ERR(raptor.class)) {
+ printk(KERN_ERR "raptor: class_create failed\n");
+ return -1;
+ }
+
+ raptor.dev = MKDEV(MAJOR(raptor.base), 0);
+
+ raptor.device = device_create(raptor.class, NULL, raptor.dev, NULL, "raptor");
+
+ if (IS_ERR(raptor.device)) {
+ printk(KERN_ERR "raptor: device_create failed\n");
+ return -1;
+ }
+
+ cdev_init(&raptor.cdev, &raptor_fops);
+
+ if (cdev_add(&raptor.cdev, raptor.dev, 1) < 0) {
+ printk(KERN_ERR "raptor: cdev_add failed\n");
+ return -1;
+ }
+
+ if (pci_register_driver(&pci_driver) != 0) {
+ printk(KERN_ALERT "raptor: pci driver NOT loaded\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "raptor: module inserted\n");
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO "raptor: removing module...\n");
+
+ pci_unregister_driver(&pci_driver);
+
+ cdev_del(&raptor.cdev);
+ device_destroy(raptor.class, raptor.dev);
+
+ class_destroy(raptor.class);
+ unregister_chrdev_region(raptor.base, 1);
+
+ kfree(raptor.send_packets);
+ kfree(raptor.recv_packets);
+
+ memset(&raptor, 0, sizeof(raptor));
+
+ printk(KERN_INFO "raptor: module removed\n");
+}