diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/Makefile | 7 | ||||
-rw-r--r-- | linux/phy_conf.h | 728 | ||||
-rw-r--r-- | linux/raptor.c | 940 |
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"); +} |