tiocx.c 12 KB

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