tiocx.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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 <asm/sn/l1.h>
  24. #include <asm/sn/module.h>
  25. #include "tio.h"
  26. #include "xtalk/xwidgetdev.h"
  27. #include "xtalk/hubdev.h"
  28. #define CX_DEV_NONE 0
  29. #define DEVICE_NAME "tiocx"
  30. #define WIDGET_ID 0
  31. #define TIOCX_DEBUG 0
  32. #if TIOCX_DEBUG
  33. #define DBG(fmt...) printk(KERN_ALERT fmt)
  34. #else
  35. #define DBG(fmt...)
  36. #endif
  37. struct device_attribute dev_attr_cxdev_control;
  38. /**
  39. * tiocx_match - Try to match driver id list with device.
  40. * @dev: device pointer
  41. * @drv: driver pointer
  42. *
  43. * Returns 1 if match, 0 otherwise.
  44. */
  45. static int tiocx_match(struct device *dev, struct device_driver *drv)
  46. {
  47. struct cx_dev *cx_dev = to_cx_dev(dev);
  48. struct cx_drv *cx_drv = to_cx_driver(drv);
  49. const struct cx_device_id *ids = cx_drv->id_table;
  50. if (!ids)
  51. return 0;
  52. while (ids->part_num) {
  53. if (ids->part_num == cx_dev->cx_id.part_num)
  54. return 1;
  55. ids++;
  56. }
  57. return 0;
  58. }
  59. static int tiocx_hotplug(struct device *dev, char **envp, int num_envp,
  60. char *buffer, int buffer_size)
  61. {
  62. return -ENODEV;
  63. }
  64. static void tiocx_bus_release(struct device *dev)
  65. {
  66. kfree(to_cx_dev(dev));
  67. }
  68. struct bus_type tiocx_bus_type = {
  69. .name = "tiocx",
  70. .match = tiocx_match,
  71. .hotplug = tiocx_hotplug,
  72. };
  73. /**
  74. * cx_device_match - Find cx_device in the id table.
  75. * @ids: id table from driver
  76. * @cx_device: part/mfg id for the device
  77. *
  78. */
  79. static const struct cx_device_id *cx_device_match(const struct cx_device_id
  80. *ids,
  81. struct cx_dev *cx_device)
  82. {
  83. /*
  84. * NOTES: We may want to check for CX_ANY_ID too.
  85. * Do we want to match against nasid too?
  86. * CX_DEV_NONE == 0, if the driver tries to register for
  87. * part/mfg == 0 we should return no-match (NULL) here.
  88. */
  89. while (ids->part_num && ids->mfg_num) {
  90. if (ids->part_num == cx_device->cx_id.part_num &&
  91. ids->mfg_num == cx_device->cx_id.mfg_num)
  92. return ids;
  93. ids++;
  94. }
  95. return NULL;
  96. }
  97. /**
  98. * cx_device_probe - Look for matching device.
  99. * Call driver probe routine if found.
  100. * @cx_driver: driver table (cx_drv struct) from driver
  101. * @cx_device: part/mfg id for the device
  102. */
  103. static int cx_device_probe(struct device *dev)
  104. {
  105. const struct cx_device_id *id;
  106. struct cx_drv *cx_drv = to_cx_driver(dev->driver);
  107. struct cx_dev *cx_dev = to_cx_dev(dev);
  108. int error = 0;
  109. if (!cx_dev->driver && cx_drv->probe) {
  110. id = cx_device_match(cx_drv->id_table, cx_dev);
  111. if (id) {
  112. if ((error = cx_drv->probe(cx_dev, id)) < 0)
  113. return error;
  114. else
  115. cx_dev->driver = cx_drv;
  116. }
  117. }
  118. return error;
  119. }
  120. /**
  121. * cx_driver_remove - Remove driver from device struct.
  122. * @dev: device
  123. */
  124. static int cx_driver_remove(struct device *dev)
  125. {
  126. struct cx_dev *cx_dev = to_cx_dev(dev);
  127. struct cx_drv *cx_drv = cx_dev->driver;
  128. if (cx_drv->remove)
  129. cx_drv->remove(cx_dev);
  130. cx_dev->driver = NULL;
  131. return 0;
  132. }
  133. /**
  134. * cx_driver_register - Register the driver.
  135. * @cx_driver: driver table (cx_drv struct) from driver
  136. *
  137. * Called from the driver init routine to register a driver.
  138. * The cx_drv struct contains the driver name, a pointer to
  139. * a table of part/mfg numbers and a pointer to the driver's
  140. * probe/attach routine.
  141. */
  142. int cx_driver_register(struct cx_drv *cx_driver)
  143. {
  144. cx_driver->driver.name = cx_driver->name;
  145. cx_driver->driver.bus = &tiocx_bus_type;
  146. cx_driver->driver.probe = cx_device_probe;
  147. cx_driver->driver.remove = cx_driver_remove;
  148. return driver_register(&cx_driver->driver);
  149. }
  150. /**
  151. * cx_driver_unregister - Unregister the driver.
  152. * @cx_driver: driver table (cx_drv struct) from driver
  153. */
  154. int cx_driver_unregister(struct cx_drv *cx_driver)
  155. {
  156. driver_unregister(&cx_driver->driver);
  157. return 0;
  158. }
  159. /**
  160. * cx_device_register - Register a device.
  161. * @nasid: device's nasid
  162. * @part_num: device's part number
  163. * @mfg_num: device's manufacturer number
  164. * @hubdev: hub info associated with this device
  165. *
  166. */
  167. int
  168. cx_device_register(nasid_t nasid, int part_num, int mfg_num,
  169. struct hubdev_info *hubdev)
  170. {
  171. struct cx_dev *cx_dev;
  172. cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL);
  173. DBG("cx_dev= 0x%p\n", cx_dev);
  174. if (cx_dev == NULL)
  175. return -ENOMEM;
  176. cx_dev->cx_id.part_num = part_num;
  177. cx_dev->cx_id.mfg_num = mfg_num;
  178. cx_dev->cx_id.nasid = nasid;
  179. cx_dev->hubdev = hubdev;
  180. cx_dev->dev.parent = NULL;
  181. cx_dev->dev.bus = &tiocx_bus_type;
  182. cx_dev->dev.release = tiocx_bus_release;
  183. snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x",
  184. cx_dev->cx_id.nasid, cx_dev->cx_id.part_num);
  185. device_register(&cx_dev->dev);
  186. get_device(&cx_dev->dev);
  187. device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
  188. return 0;
  189. }
  190. /**
  191. * cx_device_unregister - Unregister a device.
  192. * @cx_dev: part/mfg id for the device
  193. */
  194. int cx_device_unregister(struct cx_dev *cx_dev)
  195. {
  196. put_device(&cx_dev->dev);
  197. device_unregister(&cx_dev->dev);
  198. return 0;
  199. }
  200. /**
  201. * cx_device_reload - Reload the device.
  202. * @nasid: device's nasid
  203. * @part_num: device's part number
  204. * @mfg_num: device's manufacturer number
  205. *
  206. * Remove the device associated with 'nasid' from device list and then
  207. * call device-register with the given part/mfg numbers.
  208. */
  209. static int cx_device_reload(struct cx_dev *cx_dev)
  210. {
  211. device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control);
  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. return 1;
  336. }
  337. return 0;
  338. }
  339. static int bitstream_loaded(nasid_t nasid)
  340. {
  341. uint64_t cx_credits;
  342. cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3);
  343. cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK;
  344. DBG("cx_credits= 0x%lx\n", cx_credits);
  345. return (cx_credits == 0xf) ? 1 : 0;
  346. }
  347. static int tiocx_reload(struct cx_dev *cx_dev)
  348. {
  349. int part_num = CX_DEV_NONE;
  350. int mfg_num = CX_DEV_NONE;
  351. nasid_t nasid = cx_dev->cx_id.nasid;
  352. if (bitstream_loaded(nasid)) {
  353. uint64_t cx_id;
  354. cx_id =
  355. *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
  356. WIDGET_ID);
  357. part_num = XWIDGET_PART_NUM(cx_id);
  358. mfg_num = XWIDGET_MFG_NUM(cx_id);
  359. DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num);
  360. /* just ignore it if it's a CE */
  361. if (part_num == TIO_CE_ASIC_PARTNUM)
  362. return 0;
  363. }
  364. cx_dev->cx_id.part_num = part_num;
  365. cx_dev->cx_id.mfg_num = mfg_num;
  366. /*
  367. * Delete old device and register the new one. It's ok if
  368. * part_num/mfg_num == CX_DEV_NONE. We want to register
  369. * devices in the table even if a bitstream isn't loaded.
  370. * That allows use to see that a bitstream isn't loaded via
  371. * TIOCX_IOCTL_DEV_LIST.
  372. */
  373. return cx_device_reload(cx_dev);
  374. }
  375. static ssize_t show_cxdev_control(struct device *dev, struct device_attribute *attr, char *buf)
  376. {
  377. struct cx_dev *cx_dev = to_cx_dev(dev);
  378. return sprintf(buf, "0x%x 0x%x 0x%x %d\n",
  379. cx_dev->cx_id.nasid,
  380. cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num,
  381. tiocx_btchar_get(cx_dev->cx_id.nasid));
  382. }
  383. static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *attr, const char *buf,
  384. size_t count)
  385. {
  386. int n;
  387. struct cx_dev *cx_dev = to_cx_dev(dev);
  388. if (!capable(CAP_SYS_ADMIN))
  389. return -EPERM;
  390. if (count <= 0)
  391. return 0;
  392. n = simple_strtoul(buf, NULL, 0);
  393. switch (n) {
  394. case 1:
  395. tiocx_reload(cx_dev);
  396. break;
  397. case 3:
  398. tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
  399. break;
  400. default:
  401. break;
  402. }
  403. return count;
  404. }
  405. DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control);
  406. static int __init tiocx_init(void)
  407. {
  408. cnodeid_t cnodeid;
  409. int found_tiocx_device = 0;
  410. bus_register(&tiocx_bus_type);
  411. for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
  412. nasid_t nasid;
  413. if ((nasid = cnodeid_to_nasid(cnodeid)) < 0)
  414. break; /* No more nasids .. bail out of loop */
  415. if ((nasid & 0x1) && is_fpga_brick(nasid)) {
  416. struct hubdev_info *hubdev;
  417. struct xwidget_info *widgetp;
  418. DBG("Found TIO at nasid 0x%x\n", nasid);
  419. hubdev =
  420. (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo);
  421. widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET];
  422. /* The CE hangs off of the CX port but is not an FPGA */
  423. if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM)
  424. continue;
  425. tio_corelet_reset(nasid, TIOCX_CORELET);
  426. tio_conveyor_enable(nasid);
  427. if (cx_device_register
  428. (nasid, widgetp->xwi_hwid.part_num,
  429. widgetp->xwi_hwid.mfg_num, hubdev) < 0)
  430. return -ENXIO;
  431. else
  432. found_tiocx_device++;
  433. }
  434. }
  435. /* It's ok if we find zero devices. */
  436. DBG("found_tiocx_device= %d\n", found_tiocx_device);
  437. return 0;
  438. }
  439. static int cx_remove_device(struct device * dev, void * data)
  440. {
  441. struct cx_dev *cx_dev = to_cx_dev(dev);
  442. device_remove_file(dev, &dev_attr_cxdev_control);
  443. cx_device_unregister(cx_dev);
  444. return 0;
  445. }
  446. static void __exit tiocx_exit(void)
  447. {
  448. DBG("tiocx_exit\n");
  449. /*
  450. * Unregister devices.
  451. */
  452. bus_for_each_dev(&tiocx_bus_type, NULL, NULL, cx_remove_device);
  453. bus_unregister(&tiocx_bus_type);
  454. }
  455. module_init(tiocx_init);
  456. module_exit(tiocx_exit);
  457. /************************************************************************
  458. * Module licensing and description
  459. ************************************************************************/
  460. MODULE_LICENSE("GPL");
  461. MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
  462. MODULE_DESCRIPTION("TIOCX module");
  463. MODULE_SUPPORTED_DEVICE(DEVICE_NAME);