tiocx.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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/slab.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/proc_fs.h>
  13. #include <linux/device.h>
  14. #include <linux/delay.h>
  15. #include <asm/system.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 = kzalloc(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",
  184. cx_dev->cx_id.nasid);
  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. cx_device_unregister(cx_dev);
  212. return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
  213. cx_dev->cx_id.mfg_num, cx_dev->hubdev);
  214. }
  215. static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget,
  216. u64 sn_irq_info,
  217. int req_irq, nasid_t req_nasid,
  218. int req_slice)
  219. {
  220. struct ia64_sal_retval rv;
  221. rv.status = 0;
  222. rv.v0 = 0;
  223. ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
  224. SAL_INTR_ALLOC, nasid,
  225. widget, sn_irq_info, req_irq,
  226. req_nasid, req_slice);
  227. return rv.status;
  228. }
  229. static inline void tiocx_intr_free(nasid_t nasid, int widget,
  230. struct sn_irq_info *sn_irq_info)
  231. {
  232. struct ia64_sal_retval rv;
  233. rv.status = 0;
  234. rv.v0 = 0;
  235. ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
  236. SAL_INTR_FREE, nasid,
  237. widget, sn_irq_info->irq_irq,
  238. sn_irq_info->irq_cookie, 0, 0);
  239. }
  240. struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq,
  241. nasid_t req_nasid, int slice)
  242. {
  243. struct sn_irq_info *sn_irq_info;
  244. int status;
  245. int sn_irq_size = sizeof(struct sn_irq_info);
  246. if ((nasid & 1) == 0)
  247. return NULL;
  248. sn_irq_info = kmalloc(sn_irq_size, GFP_KERNEL);
  249. if (sn_irq_info == NULL)
  250. return NULL;
  251. memset(sn_irq_info, 0x0, sn_irq_size);
  252. status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq,
  253. req_nasid, slice);
  254. if (status) {
  255. kfree(sn_irq_info);
  256. return NULL;
  257. } else {
  258. return sn_irq_info;
  259. }
  260. }
  261. void tiocx_irq_free(struct sn_irq_info *sn_irq_info)
  262. {
  263. uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
  264. nasid_t nasid = NASID_GET(bridge);
  265. int widget;
  266. if (nasid & 1) {
  267. widget = TIO_SWIN_WIDGETNUM(bridge);
  268. tiocx_intr_free(nasid, widget, sn_irq_info);
  269. kfree(sn_irq_info);
  270. }
  271. }
  272. uint64_t tiocx_dma_addr(uint64_t addr)
  273. {
  274. return PHYS_TO_TIODMA(addr);
  275. }
  276. uint64_t tiocx_swin_base(int nasid)
  277. {
  278. return TIO_SWIN_BASE(nasid, TIOCX_CORELET);
  279. }
  280. EXPORT_SYMBOL(cx_driver_register);
  281. EXPORT_SYMBOL(cx_driver_unregister);
  282. EXPORT_SYMBOL(cx_device_register);
  283. EXPORT_SYMBOL(cx_device_unregister);
  284. EXPORT_SYMBOL(tiocx_irq_alloc);
  285. EXPORT_SYMBOL(tiocx_irq_free);
  286. EXPORT_SYMBOL(tiocx_bus_type);
  287. EXPORT_SYMBOL(tiocx_dma_addr);
  288. EXPORT_SYMBOL(tiocx_swin_base);
  289. static void tio_conveyor_set(nasid_t nasid, int enable_flag)
  290. {
  291. uint64_t ice_frz;
  292. uint64_t disable_cb = (1ull << 61);
  293. if (!(nasid & 1))
  294. return;
  295. ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG);
  296. if (enable_flag) {
  297. if (!(ice_frz & disable_cb)) /* already enabled */
  298. return;
  299. ice_frz &= ~disable_cb;
  300. } else {
  301. if (ice_frz & disable_cb) /* already disabled */
  302. return;
  303. ice_frz |= disable_cb;
  304. }
  305. DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz);
  306. REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz);
  307. }
  308. #define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1)
  309. #define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0)
  310. static void tio_corelet_reset(nasid_t nasid, int corelet)
  311. {
  312. if (!(nasid & 1))
  313. return;
  314. REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet);
  315. udelay(2000);
  316. REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0);
  317. udelay(2000);
  318. }
  319. static int tiocx_btchar_get(int nasid)
  320. {
  321. moduleid_t module_id;
  322. geoid_t geoid;
  323. int cnodeid;
  324. cnodeid = nasid_to_cnodeid(nasid);
  325. geoid = cnodeid_get_geoid(cnodeid);
  326. module_id = geo_module(geoid);
  327. return MODULE_GET_BTCHAR(module_id);
  328. }
  329. static int is_fpga_brick(int nasid)
  330. {
  331. switch (tiocx_btchar_get(nasid)) {
  332. case L1_BRICKTYPE_SA:
  333. case L1_BRICKTYPE_ATHENA:
  334. case L1_BRICKTYPE_DAYTONA:
  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 uint64_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. tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
  396. tiocx_reload(cx_dev);
  397. break;
  398. case 2:
  399. tiocx_reload(cx_dev);
  400. break;
  401. case 3:
  402. tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
  403. break;
  404. default:
  405. break;
  406. }
  407. return count;
  408. }
  409. DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control);
  410. static int __init tiocx_init(void)
  411. {
  412. cnodeid_t cnodeid;
  413. int found_tiocx_device = 0;
  414. if (!ia64_platform_is("sn2"))
  415. return -ENODEV;
  416. bus_register(&tiocx_bus_type);
  417. for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
  418. nasid_t nasid;
  419. if ((nasid = cnodeid_to_nasid(cnodeid)) < 0)
  420. break; /* No more nasids .. bail out of loop */
  421. if ((nasid & 0x1) && is_fpga_brick(nasid)) {
  422. struct hubdev_info *hubdev;
  423. struct xwidget_info *widgetp;
  424. DBG("Found TIO at nasid 0x%x\n", nasid);
  425. hubdev =
  426. (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo);
  427. widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET];
  428. /* The CE hangs off of the CX port but is not an FPGA */
  429. if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM)
  430. continue;
  431. tio_corelet_reset(nasid, TIOCX_CORELET);
  432. tio_conveyor_enable(nasid);
  433. if (cx_device_register
  434. (nasid, widgetp->xwi_hwid.part_num,
  435. widgetp->xwi_hwid.mfg_num, hubdev) < 0)
  436. return -ENXIO;
  437. else
  438. found_tiocx_device++;
  439. }
  440. }
  441. /* It's ok if we find zero devices. */
  442. DBG("found_tiocx_device= %d\n", found_tiocx_device);
  443. return 0;
  444. }
  445. static int cx_remove_device(struct device * dev, void * data)
  446. {
  447. struct cx_dev *cx_dev = to_cx_dev(dev);
  448. device_remove_file(dev, &dev_attr_cxdev_control);
  449. cx_device_unregister(cx_dev);
  450. return 0;
  451. }
  452. static void __exit tiocx_exit(void)
  453. {
  454. DBG("tiocx_exit\n");
  455. /*
  456. * Unregister devices.
  457. */
  458. bus_for_each_dev(&tiocx_bus_type, NULL, NULL, cx_remove_device);
  459. bus_unregister(&tiocx_bus_type);
  460. }
  461. subsys_initcall(tiocx_init);
  462. module_exit(tiocx_exit);
  463. /************************************************************************
  464. * Module licensing and description
  465. ************************************************************************/
  466. MODULE_LICENSE("GPL");
  467. MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
  468. MODULE_DESCRIPTION("TIOCX module");
  469. MODULE_SUPPORTED_DEVICE(DEVICE_NAME);