tiocx.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
  7. */
  8. #include <linux/module.h>
  9. #include <linux/kernel.h>
  10. #include <linux/version.h>
  11. #include <linux/slab.h>
  12. #include <linux/spinlock.h>
  13. #include <linux/proc_fs.h>
  14. #include <linux/device.h>
  15. #include <linux/delay.h>
  16. #include <asm/system.h>
  17. #include <asm/uaccess.h>
  18. #include <asm/sn/sn_sal.h>
  19. #include <asm/sn/addrs.h>
  20. #include <asm/sn/io.h>
  21. #include <asm/sn/types.h>
  22. #include <asm/sn/shubio.h>
  23. #include <asm/sn/tiocx.h>
  24. #include <asm/sn/l1.h>
  25. #include <asm/sn/module.h>
  26. #include "tio.h"
  27. #include "xtalk/xwidgetdev.h"
  28. #include "xtalk/hubdev.h"
  29. #define CX_DEV_NONE 0
  30. #define DEVICE_NAME "tiocx"
  31. #define WIDGET_ID 0
  32. #define TIOCX_DEBUG 0
  33. #if TIOCX_DEBUG
  34. #define DBG(fmt...) printk(KERN_ALERT fmt)
  35. #else
  36. #define DBG(fmt...)
  37. #endif
  38. struct device_attribute dev_attr_cxdev_control;
  39. /**
  40. * tiocx_match - Try to match driver id list with device.
  41. * @dev: device pointer
  42. * @drv: driver pointer
  43. *
  44. * Returns 1 if match, 0 otherwise.
  45. */
  46. static int tiocx_match(struct device *dev, struct device_driver *drv)
  47. {
  48. struct cx_dev *cx_dev = to_cx_dev(dev);
  49. struct cx_drv *cx_drv = to_cx_driver(drv);
  50. const struct cx_device_id *ids = cx_drv->id_table;
  51. if (!ids)
  52. return 0;
  53. while (ids->part_num) {
  54. if (ids->part_num == cx_dev->cx_id.part_num)
  55. return 1;
  56. ids++;
  57. }
  58. return 0;
  59. }
  60. static int tiocx_hotplug(struct device *dev, char **envp, int num_envp,
  61. char *buffer, int buffer_size)
  62. {
  63. return -ENODEV;
  64. }
  65. static void tiocx_bus_release(struct device *dev)
  66. {
  67. kfree(to_cx_dev(dev));
  68. }
  69. struct bus_type tiocx_bus_type = {
  70. .name = "tiocx",
  71. .match = tiocx_match,
  72. .hotplug = tiocx_hotplug,
  73. };
  74. /**
  75. * cx_device_match - Find cx_device in the id table.
  76. * @ids: id table from driver
  77. * @cx_device: part/mfg id for the device
  78. *
  79. */
  80. static const struct cx_device_id *cx_device_match(const struct cx_device_id
  81. *ids,
  82. struct cx_dev *cx_device)
  83. {
  84. /*
  85. * NOTES: We may want to check for CX_ANY_ID too.
  86. * Do we want to match against nasid too?
  87. * CX_DEV_NONE == 0, if the driver tries to register for
  88. * part/mfg == 0 we should return no-match (NULL) here.
  89. */
  90. while (ids->part_num && ids->mfg_num) {
  91. if (ids->part_num == cx_device->cx_id.part_num &&
  92. ids->mfg_num == cx_device->cx_id.mfg_num)
  93. return ids;
  94. ids++;
  95. }
  96. return NULL;
  97. }
  98. /**
  99. * cx_device_probe - Look for matching device.
  100. * Call driver probe routine if found.
  101. * @cx_driver: driver table (cx_drv struct) from driver
  102. * @cx_device: part/mfg id for the device
  103. */
  104. static int cx_device_probe(struct device *dev)
  105. {
  106. const struct cx_device_id *id;
  107. struct cx_drv *cx_drv = to_cx_driver(dev->driver);
  108. struct cx_dev *cx_dev = to_cx_dev(dev);
  109. int error = 0;
  110. if (!cx_dev->driver && cx_drv->probe) {
  111. id = cx_device_match(cx_drv->id_table, cx_dev);
  112. if (id) {
  113. if ((error = cx_drv->probe(cx_dev, id)) < 0)
  114. return error;
  115. else
  116. cx_dev->driver = cx_drv;
  117. }
  118. }
  119. return error;
  120. }
  121. /**
  122. * cx_driver_remove - Remove driver from device struct.
  123. * @dev: device
  124. */
  125. static int cx_driver_remove(struct device *dev)
  126. {
  127. struct cx_dev *cx_dev = to_cx_dev(dev);
  128. struct cx_drv *cx_drv = cx_dev->driver;
  129. if (cx_drv->remove)
  130. cx_drv->remove(cx_dev);
  131. cx_dev->driver = NULL;
  132. return 0;
  133. }
  134. /**
  135. * cx_driver_register - Register the driver.
  136. * @cx_driver: driver table (cx_drv struct) from driver
  137. *
  138. * Called from the driver init routine to register a driver.
  139. * The cx_drv struct contains the driver name, a pointer to
  140. * a table of part/mfg numbers and a pointer to the driver's
  141. * probe/attach routine.
  142. */
  143. int cx_driver_register(struct cx_drv *cx_driver)
  144. {
  145. cx_driver->driver.name = cx_driver->name;
  146. cx_driver->driver.bus = &tiocx_bus_type;
  147. cx_driver->driver.probe = cx_device_probe;
  148. cx_driver->driver.remove = cx_driver_remove;
  149. return driver_register(&cx_driver->driver);
  150. }
  151. /**
  152. * cx_driver_unregister - Unregister the driver.
  153. * @cx_driver: driver table (cx_drv struct) from driver
  154. */
  155. int cx_driver_unregister(struct cx_drv *cx_driver)
  156. {
  157. driver_unregister(&cx_driver->driver);
  158. return 0;
  159. }
  160. /**
  161. * cx_device_register - Register a device.
  162. * @nasid: device's nasid
  163. * @part_num: device's part number
  164. * @mfg_num: device's manufacturer number
  165. * @hubdev: hub info associated with this device
  166. *
  167. */
  168. int
  169. cx_device_register(nasid_t nasid, int part_num, int mfg_num,
  170. struct hubdev_info *hubdev)
  171. {
  172. struct cx_dev *cx_dev;
  173. cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL);
  174. DBG("cx_dev= 0x%p\n", cx_dev);
  175. if (cx_dev == NULL)
  176. return -ENOMEM;
  177. cx_dev->cx_id.part_num = part_num;
  178. cx_dev->cx_id.mfg_num = mfg_num;
  179. cx_dev->cx_id.nasid = nasid;
  180. cx_dev->hubdev = hubdev;
  181. cx_dev->dev.parent = NULL;
  182. cx_dev->dev.bus = &tiocx_bus_type;
  183. cx_dev->dev.release = tiocx_bus_release;
  184. snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d",
  185. cx_dev->cx_id.nasid);
  186. device_register(&cx_dev->dev);
  187. get_device(&cx_dev->dev);
  188. device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
  189. return 0;
  190. }
  191. /**
  192. * cx_device_unregister - Unregister a device.
  193. * @cx_dev: part/mfg id for the device
  194. */
  195. int cx_device_unregister(struct cx_dev *cx_dev)
  196. {
  197. put_device(&cx_dev->dev);
  198. device_unregister(&cx_dev->dev);
  199. return 0;
  200. }
  201. /**
  202. * cx_device_reload - Reload the device.
  203. * @nasid: device's nasid
  204. * @part_num: device's part number
  205. * @mfg_num: device's manufacturer number
  206. *
  207. * Remove the device associated with 'nasid' from device list and then
  208. * call device-register with the given part/mfg numbers.
  209. */
  210. static int cx_device_reload(struct cx_dev *cx_dev)
  211. {
  212. cx_device_unregister(cx_dev);
  213. return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
  214. cx_dev->cx_id.mfg_num, cx_dev->hubdev);
  215. }
  216. static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget,
  217. u64 sn_irq_info,
  218. int req_irq, nasid_t req_nasid,
  219. int req_slice)
  220. {
  221. struct ia64_sal_retval rv;
  222. rv.status = 0;
  223. rv.v0 = 0;
  224. ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
  225. SAL_INTR_ALLOC, nasid,
  226. widget, sn_irq_info, req_irq,
  227. req_nasid, req_slice);
  228. return rv.status;
  229. }
  230. static inline void tiocx_intr_free(nasid_t nasid, int widget,
  231. struct sn_irq_info *sn_irq_info)
  232. {
  233. struct ia64_sal_retval rv;
  234. rv.status = 0;
  235. rv.v0 = 0;
  236. ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
  237. SAL_INTR_FREE, nasid,
  238. widget, sn_irq_info->irq_irq,
  239. sn_irq_info->irq_cookie, 0, 0);
  240. }
  241. struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq,
  242. nasid_t req_nasid, int slice)
  243. {
  244. struct sn_irq_info *sn_irq_info;
  245. int status;
  246. int sn_irq_size = sizeof(struct sn_irq_info);
  247. if ((nasid & 1) == 0)
  248. return NULL;
  249. sn_irq_info = kmalloc(sn_irq_size, GFP_KERNEL);
  250. if (sn_irq_info == NULL)
  251. return NULL;
  252. memset(sn_irq_info, 0x0, sn_irq_size);
  253. status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq,
  254. req_nasid, slice);
  255. if (status) {
  256. kfree(sn_irq_info);
  257. return NULL;
  258. } else {
  259. return sn_irq_info;
  260. }
  261. }
  262. void tiocx_irq_free(struct sn_irq_info *sn_irq_info)
  263. {
  264. uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
  265. nasid_t nasid = NASID_GET(bridge);
  266. int widget;
  267. if (nasid & 1) {
  268. widget = TIO_SWIN_WIDGETNUM(bridge);
  269. tiocx_intr_free(nasid, widget, sn_irq_info);
  270. kfree(sn_irq_info);
  271. }
  272. }
  273. uint64_t tiocx_dma_addr(uint64_t addr)
  274. {
  275. return PHYS_TO_TIODMA(addr);
  276. }
  277. uint64_t tiocx_swin_base(int nasid)
  278. {
  279. return TIO_SWIN_BASE(nasid, TIOCX_CORELET);
  280. }
  281. EXPORT_SYMBOL(cx_driver_register);
  282. EXPORT_SYMBOL(cx_driver_unregister);
  283. EXPORT_SYMBOL(cx_device_register);
  284. EXPORT_SYMBOL(cx_device_unregister);
  285. EXPORT_SYMBOL(tiocx_irq_alloc);
  286. EXPORT_SYMBOL(tiocx_irq_free);
  287. EXPORT_SYMBOL(tiocx_bus_type);
  288. EXPORT_SYMBOL(tiocx_dma_addr);
  289. EXPORT_SYMBOL(tiocx_swin_base);
  290. static void tio_conveyor_set(nasid_t nasid, int enable_flag)
  291. {
  292. uint64_t ice_frz;
  293. uint64_t disable_cb = (1ull << 61);
  294. if (!(nasid & 1))
  295. return;
  296. ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG);
  297. if (enable_flag) {
  298. if (!(ice_frz & disable_cb)) /* already enabled */
  299. return;
  300. ice_frz &= ~disable_cb;
  301. } else {
  302. if (ice_frz & disable_cb) /* already disabled */
  303. return;
  304. ice_frz |= disable_cb;
  305. }
  306. DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz);
  307. REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz);
  308. }
  309. #define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1)
  310. #define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0)
  311. static void tio_corelet_reset(nasid_t nasid, int corelet)
  312. {
  313. if (!(nasid & 1))
  314. return;
  315. REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet);
  316. udelay(2000);
  317. REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0);
  318. udelay(2000);
  319. }
  320. static int tiocx_btchar_get(int nasid)
  321. {
  322. moduleid_t module_id;
  323. geoid_t geoid;
  324. int cnodeid;
  325. cnodeid = nasid_to_cnodeid(nasid);
  326. geoid = cnodeid_get_geoid(cnodeid);
  327. module_id = geo_module(geoid);
  328. return MODULE_GET_BTCHAR(module_id);
  329. }
  330. static int is_fpga_brick(int nasid)
  331. {
  332. switch (tiocx_btchar_get(nasid)) {
  333. case L1_BRICKTYPE_SA:
  334. case L1_BRICKTYPE_ATHENA:
  335. case L1_BRICKTYPE_DAYTONA:
  336. return 1;
  337. }
  338. return 0;
  339. }
  340. static int bitstream_loaded(nasid_t nasid)
  341. {
  342. uint64_t cx_credits;
  343. cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3);
  344. cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK;
  345. DBG("cx_credits= 0x%lx\n", cx_credits);
  346. return (cx_credits == 0xf) ? 1 : 0;
  347. }
  348. static int tiocx_reload(struct cx_dev *cx_dev)
  349. {
  350. int part_num = CX_DEV_NONE;
  351. int mfg_num = CX_DEV_NONE;
  352. nasid_t nasid = cx_dev->cx_id.nasid;
  353. if (bitstream_loaded(nasid)) {
  354. uint64_t cx_id;
  355. cx_id =
  356. *(volatile uint64_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
  357. WIDGET_ID);
  358. part_num = XWIDGET_PART_NUM(cx_id);
  359. mfg_num = XWIDGET_MFG_NUM(cx_id);
  360. DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num);
  361. /* just ignore it if it's a CE */
  362. if (part_num == TIO_CE_ASIC_PARTNUM)
  363. return 0;
  364. }
  365. cx_dev->cx_id.part_num = part_num;
  366. cx_dev->cx_id.mfg_num = mfg_num;
  367. /*
  368. * Delete old device and register the new one. It's ok if
  369. * part_num/mfg_num == CX_DEV_NONE. We want to register
  370. * devices in the table even if a bitstream isn't loaded.
  371. * That allows use to see that a bitstream isn't loaded via
  372. * TIOCX_IOCTL_DEV_LIST.
  373. */
  374. return cx_device_reload(cx_dev);
  375. }
  376. static ssize_t show_cxdev_control(struct device *dev, struct device_attribute *attr, char *buf)
  377. {
  378. struct cx_dev *cx_dev = to_cx_dev(dev);
  379. return sprintf(buf, "0x%x 0x%x 0x%x %d\n",
  380. cx_dev->cx_id.nasid,
  381. cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num,
  382. tiocx_btchar_get(cx_dev->cx_id.nasid));
  383. }
  384. static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *attr, const char *buf,
  385. size_t count)
  386. {
  387. int n;
  388. struct cx_dev *cx_dev = to_cx_dev(dev);
  389. if (!capable(CAP_SYS_ADMIN))
  390. return -EPERM;
  391. if (count <= 0)
  392. return 0;
  393. n = simple_strtoul(buf, NULL, 0);
  394. switch (n) {
  395. case 1:
  396. tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
  397. tiocx_reload(cx_dev);
  398. break;
  399. case 2:
  400. tiocx_reload(cx_dev);
  401. break;
  402. case 3:
  403. tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
  404. break;
  405. default:
  406. break;
  407. }
  408. return count;
  409. }
  410. DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control);
  411. static int __init tiocx_init(void)
  412. {
  413. cnodeid_t cnodeid;
  414. int found_tiocx_device = 0;
  415. if (!ia64_platform_is("sn2"))
  416. return -ENODEV;
  417. bus_register(&tiocx_bus_type);
  418. for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
  419. nasid_t nasid;
  420. if ((nasid = cnodeid_to_nasid(cnodeid)) < 0)
  421. break; /* No more nasids .. bail out of loop */
  422. if ((nasid & 0x1) && is_fpga_brick(nasid)) {
  423. struct hubdev_info *hubdev;
  424. struct xwidget_info *widgetp;
  425. DBG("Found TIO at nasid 0x%x\n", nasid);
  426. hubdev =
  427. (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo);
  428. widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET];
  429. /* The CE hangs off of the CX port but is not an FPGA */
  430. if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM)
  431. continue;
  432. tio_corelet_reset(nasid, TIOCX_CORELET);
  433. tio_conveyor_enable(nasid);
  434. if (cx_device_register
  435. (nasid, widgetp->xwi_hwid.part_num,
  436. widgetp->xwi_hwid.mfg_num, hubdev) < 0)
  437. return -ENXIO;
  438. else
  439. found_tiocx_device++;
  440. }
  441. }
  442. /* It's ok if we find zero devices. */
  443. DBG("found_tiocx_device= %d\n", found_tiocx_device);
  444. return 0;
  445. }
  446. static int cx_remove_device(struct device * dev, void * data)
  447. {
  448. struct cx_dev *cx_dev = to_cx_dev(dev);
  449. device_remove_file(dev, &dev_attr_cxdev_control);
  450. cx_device_unregister(cx_dev);
  451. return 0;
  452. }
  453. static void __exit tiocx_exit(void)
  454. {
  455. DBG("tiocx_exit\n");
  456. /*
  457. * Unregister devices.
  458. */
  459. bus_for_each_dev(&tiocx_bus_type, NULL, NULL, cx_remove_device);
  460. bus_unregister(&tiocx_bus_type);
  461. }
  462. subsys_initcall(tiocx_init);
  463. module_exit(tiocx_exit);
  464. /************************************************************************
  465. * Module licensing and description
  466. ************************************************************************/
  467. MODULE_LICENSE("GPL");
  468. MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
  469. MODULE_DESCRIPTION("TIOCX module");
  470. MODULE_SUPPORTED_DEVICE(DEVICE_NAME);