summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
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 <[email protected]>
+ * Dimitri Staessens <[email protected]>
+ * Sander Vrijders <[email protected]>
+ *
+ * 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");
+}