pic.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-08-24 GuEe-GUI first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #define DBG_TAG "rtdm.pic"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #include <drivers/pic.h>
  16. #include <ktime.h>
  17. struct irq_traps
  18. {
  19. rt_list_t list;
  20. void *data;
  21. rt_bool_t (*handler)(void *);
  22. };
  23. static int _ipi_hash[] =
  24. {
  25. #ifdef RT_USING_SMP
  26. [RT_SCHEDULE_IPI] = RT_SCHEDULE_IPI,
  27. [RT_STOP_IPI] = RT_STOP_IPI,
  28. #endif
  29. };
  30. /* reserved ipi */
  31. static int _pirq_hash_idx = RT_ARRAY_SIZE(_ipi_hash);
  32. static struct rt_pic_irq _pirq_hash[MAX_HANDLERS] =
  33. {
  34. [0 ... MAX_HANDLERS - 1] =
  35. {
  36. .irq = -1,
  37. .hwirq = -1,
  38. .mode = RT_IRQ_MODE_NONE,
  39. .priority = RT_UINT32_MAX,
  40. .rw_lock = { },
  41. }
  42. };
  43. static struct rt_spinlock _pic_lock = { };
  44. static rt_size_t _pic_name_max = sizeof("PIC");
  45. static rt_list_t _pic_nodes = RT_LIST_OBJECT_INIT(_pic_nodes);
  46. static rt_list_t _traps_nodes = RT_LIST_OBJECT_INIT(_traps_nodes);
  47. static struct rt_pic_irq *irq2pirq(int irq)
  48. {
  49. struct rt_pic_irq *pirq = RT_NULL;
  50. if ((irq >= 0) && (irq < MAX_HANDLERS))
  51. {
  52. pirq = &_pirq_hash[irq];
  53. if (pirq->irq < 0)
  54. {
  55. pirq = RT_NULL;
  56. }
  57. }
  58. if (!pirq)
  59. {
  60. LOG_E("irq = %d is invalid", irq);
  61. }
  62. return pirq;
  63. }
  64. static void append_pic(struct rt_pic *pic)
  65. {
  66. int pic_name_len = rt_strlen(pic->ops->name);
  67. rt_list_insert_before(&_pic_nodes, &pic->list);
  68. if (pic_name_len > _pic_name_max)
  69. {
  70. _pic_name_max = pic_name_len;
  71. }
  72. }
  73. void rt_pic_default_name(struct rt_pic *pic)
  74. {
  75. if (pic)
  76. {
  77. #if RT_NAME_MAX > 0
  78. rt_strncpy(pic->parent.name, "PIC", RT_NAME_MAX - 1);
  79. pic->parent.name[RT_NAME_MAX - 1] = '\0';
  80. #else
  81. pic->parent.name = "PIC";
  82. #endif
  83. }
  84. }
  85. struct rt_pic *rt_pic_dynamic_cast(void *ptr)
  86. {
  87. struct rt_pic *pic = RT_NULL, *tmp = RT_NULL;
  88. if (ptr)
  89. {
  90. struct rt_object *obj = ptr;
  91. if (obj->type == RT_Object_Class_Unknown)
  92. {
  93. tmp = (void *)obj;
  94. }
  95. else if (obj->type == RT_Object_Class_Device)
  96. {
  97. tmp = (void *)obj + sizeof(struct rt_device);
  98. }
  99. else
  100. {
  101. tmp = (void *)obj + sizeof(struct rt_object);
  102. }
  103. if (tmp && !rt_strcmp(tmp->parent.name, "PIC"))
  104. {
  105. pic = tmp;
  106. }
  107. }
  108. return pic;
  109. }
  110. rt_err_t rt_pic_linear_irq(struct rt_pic *pic, rt_size_t irq_nr)
  111. {
  112. rt_err_t err = RT_EOK;
  113. if (pic && pic->ops && pic->ops->name)
  114. {
  115. rt_ubase_t level = rt_spin_lock_irqsave(&_pic_lock);
  116. if (_pirq_hash_idx + irq_nr <= RT_ARRAY_SIZE(_pirq_hash))
  117. {
  118. rt_list_init(&pic->list);
  119. rt_pic_default_name(pic);
  120. pic->parent.type = RT_Object_Class_Unknown;
  121. pic->irq_start = _pirq_hash_idx;
  122. pic->irq_nr = irq_nr;
  123. pic->pirqs = &_pirq_hash[_pirq_hash_idx];
  124. _pirq_hash_idx += irq_nr;
  125. append_pic(pic);
  126. LOG_D("%s alloc irqs ranges [%d, %d]", pic->ops->name,
  127. pic->irq_start, pic->irq_start + pic->irq_nr);
  128. }
  129. else
  130. {
  131. LOG_E("%s alloc %d irqs is overflow", pic->ops->name, irq_nr);
  132. err = -RT_EEMPTY;
  133. }
  134. rt_spin_unlock_irqrestore(&_pic_lock, level);
  135. }
  136. else
  137. {
  138. err = -RT_EINVAL;
  139. }
  140. return err;
  141. }
  142. static void config_pirq(struct rt_pic *pic, struct rt_pic_irq *pirq, int irq, int hwirq)
  143. {
  144. rt_ubase_t level = rt_spin_lock_irqsave(&pirq->rw_lock);
  145. if (pirq->irq < 0)
  146. {
  147. rt_list_init(&pirq->list);
  148. rt_list_init(&pirq->children_nodes);
  149. rt_list_init(&pirq->isr.list);
  150. }
  151. else if (pirq->pic != pic)
  152. {
  153. RT_ASSERT(rt_list_isempty(&pirq->list) == RT_TRUE);
  154. RT_ASSERT(rt_list_isempty(&pirq->children_nodes) == RT_TRUE);
  155. RT_ASSERT(rt_list_isempty(&pirq->isr.list) == RT_TRUE);
  156. }
  157. pirq->irq = irq;
  158. pirq->hwirq = hwirq;
  159. pirq->pic = pic;
  160. rt_spin_unlock_irqrestore(&pirq->rw_lock, level);
  161. }
  162. int rt_pic_config_ipi(struct rt_pic *pic, int ipi_index, int hwirq)
  163. {
  164. int ipi = ipi_index;
  165. struct rt_pic_irq *pirq;
  166. if (pic && ipi < RT_ARRAY_SIZE(_ipi_hash) && hwirq >= 0 && pic->ops->irq_send_ipi)
  167. {
  168. pirq = &_pirq_hash[ipi];
  169. config_pirq(pic, pirq, ipi, hwirq);
  170. for (int cpuid = 0; cpuid < RT_CPUS_NR; ++cpuid)
  171. {
  172. RT_IRQ_AFFINITY_SET(pirq->affinity, cpuid);
  173. }
  174. LOG_D("%s config %s %d to hwirq %d", pic->ops->name, "ipi", ipi, hwirq);
  175. }
  176. else
  177. {
  178. ipi = -RT_EINVAL;
  179. }
  180. return ipi;
  181. }
  182. int rt_pic_config_irq(struct rt_pic *pic, int irq_index, int hwirq)
  183. {
  184. int irq;
  185. if (pic && hwirq >= 0)
  186. {
  187. irq = pic->irq_start + irq_index;
  188. if (irq >= 0 && irq < MAX_HANDLERS)
  189. {
  190. config_pirq(pic, &_pirq_hash[irq], irq, hwirq);
  191. LOG_D("%s config %s %d to hwirq %d", pic->ops->name, "irq", irq, hwirq);
  192. }
  193. else
  194. {
  195. irq = -RT_ERROR;
  196. }
  197. }
  198. else
  199. {
  200. irq = -RT_EINVAL;
  201. }
  202. return irq;
  203. }
  204. struct rt_pic_irq *rt_pic_find_ipi(struct rt_pic *pic, int ipi_index)
  205. {
  206. struct rt_pic_irq *pirq = &_pirq_hash[ipi_index];
  207. RT_ASSERT(ipi_index < RT_ARRAY_SIZE(_ipi_hash));
  208. RT_ASSERT(pirq->pic == pic);
  209. return pirq;
  210. }
  211. struct rt_pic_irq *rt_pic_find_pirq(struct rt_pic *pic, int irq)
  212. {
  213. if (pic && irq >= pic->irq_start && irq <= pic->irq_start + pic->irq_nr)
  214. {
  215. return &pic->pirqs[irq - pic->irq_start];
  216. }
  217. return RT_NULL;
  218. }
  219. rt_err_t rt_pic_cascade(struct rt_pic_irq *pirq, int parent_irq)
  220. {
  221. rt_err_t err = RT_EOK;
  222. if (pirq && !pirq->parent && parent_irq >= 0)
  223. {
  224. struct rt_pic_irq *parent;
  225. rt_spin_lock(&pirq->rw_lock);
  226. parent = irq2pirq(parent_irq);
  227. if (parent)
  228. {
  229. pirq->parent = parent;
  230. pirq->priority = parent->priority;
  231. rt_memcpy(&pirq->affinity, &parent->affinity, sizeof(pirq->affinity));
  232. }
  233. rt_spin_unlock(&pirq->rw_lock);
  234. if (parent && pirq->pic->ops->flags & RT_PIC_F_IRQ_ROUTING)
  235. {
  236. rt_spin_lock(&parent->rw_lock);
  237. rt_list_insert_before(&parent->children_nodes, &pirq->list);
  238. rt_spin_unlock(&parent->rw_lock);
  239. }
  240. }
  241. else
  242. {
  243. err = -RT_EINVAL;
  244. }
  245. return err;
  246. }
  247. rt_err_t rt_pic_uncascade(struct rt_pic_irq *pirq)
  248. {
  249. rt_err_t err = RT_EOK;
  250. if (pirq && pirq->parent)
  251. {
  252. struct rt_pic_irq *parent;
  253. rt_spin_lock(&pirq->rw_lock);
  254. parent = pirq->parent;
  255. pirq->parent = RT_NULL;
  256. rt_spin_unlock(&pirq->rw_lock);
  257. if (parent && pirq->pic->ops->flags & RT_PIC_F_IRQ_ROUTING)
  258. {
  259. rt_spin_lock(&parent->rw_lock);
  260. rt_list_remove(&pirq->list);
  261. rt_spin_unlock(&parent->rw_lock);
  262. }
  263. }
  264. else
  265. {
  266. err = -RT_EINVAL;
  267. }
  268. return err;
  269. }
  270. rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid, const char *name, int flags)
  271. {
  272. rt_err_t err = -RT_EINVAL;
  273. struct rt_pic_irq *pirq;
  274. if (handler && name && (pirq = irq2pirq(irq)))
  275. {
  276. struct rt_pic_isr *isr = RT_NULL;
  277. rt_ubase_t level = rt_spin_lock_irqsave(&pirq->rw_lock);
  278. err = RT_EOK;
  279. if (!pirq->isr.action.handler)
  280. {
  281. /* first attach */
  282. isr = &pirq->isr;
  283. rt_list_init(&isr->list);
  284. }
  285. else
  286. {
  287. rt_spin_unlock_irqrestore(&pirq->rw_lock, level);
  288. if ((isr = rt_malloc(sizeof(*isr))))
  289. {
  290. rt_list_init(&isr->list);
  291. level = rt_spin_lock_irqsave(&pirq->rw_lock);
  292. rt_list_insert_after(&pirq->isr.list, &isr->list);
  293. }
  294. else
  295. {
  296. LOG_E("No memory to save '%s' isr", name);
  297. err = -RT_ERROR;
  298. }
  299. }
  300. if (!err)
  301. {
  302. isr->flags = flags;
  303. isr->action.handler = handler;
  304. isr->action.param = uid;
  305. #ifdef RT_USING_INTERRUPT_INFO
  306. isr->action.counter = 0;
  307. rt_strncpy(isr->action.name, name, RT_NAME_MAX - 1);
  308. isr->action.name[RT_NAME_MAX - 1] = '\0';
  309. #ifdef RT_USING_SMP
  310. rt_memset(isr->action.cpu_counter, 0, sizeof(isr->action.cpu_counter));
  311. #endif
  312. #endif
  313. rt_spin_unlock_irqrestore(&pirq->rw_lock, level);
  314. }
  315. }
  316. return err;
  317. }
  318. rt_err_t rt_pic_detach_irq(int irq, void *uid)
  319. {
  320. rt_err_t err = -RT_EINVAL;
  321. struct rt_pic_irq *pirq = irq2pirq(irq);
  322. if (pirq)
  323. {
  324. rt_bool_t will_free = RT_FALSE;
  325. struct rt_pic_isr *isr = RT_NULL;
  326. rt_ubase_t level = rt_spin_lock_irqsave(&pirq->rw_lock);
  327. isr = &pirq->isr;
  328. if (isr->action.param == uid)
  329. {
  330. if (rt_list_isempty(&isr->list))
  331. {
  332. isr->action.handler = RT_NULL;
  333. isr->action.param = RT_NULL;
  334. }
  335. else
  336. {
  337. struct rt_pic_isr *next_isr = rt_list_first_entry(&isr->list, struct rt_pic_isr, list);
  338. rt_list_remove(&next_isr->list);
  339. isr->action.handler = next_isr->action.handler;
  340. isr->action.param = next_isr->action.param;
  341. #ifdef RT_USING_INTERRUPT_INFO
  342. isr->action.counter = next_isr->action.counter;
  343. rt_strncpy(isr->action.name, next_isr->action.name, RT_NAME_MAX);
  344. #ifdef RT_USING_SMP
  345. rt_memcpy(isr->action.cpu_counter, next_isr->action.cpu_counter, sizeof(next_isr->action.cpu_counter));
  346. #endif
  347. #endif
  348. isr = next_isr;
  349. will_free = RT_TRUE;
  350. }
  351. err = RT_EOK;
  352. }
  353. else
  354. {
  355. rt_list_for_each_entry(isr, &pirq->isr.list, list)
  356. {
  357. if (isr->action.param == uid)
  358. {
  359. err = RT_EOK;
  360. will_free = RT_TRUE;
  361. rt_list_remove(&isr->list);
  362. break;
  363. }
  364. }
  365. }
  366. rt_spin_unlock_irqrestore(&pirq->rw_lock, level);
  367. if (will_free)
  368. {
  369. rt_free(isr);
  370. }
  371. }
  372. return err;
  373. }
  374. rt_err_t rt_pic_add_traps(rt_bool_t (*handler)(void *), void *data)
  375. {
  376. rt_err_t err = -RT_EINVAL;
  377. if (handler)
  378. {
  379. struct irq_traps *traps = rt_malloc(sizeof(*traps));
  380. if (traps)
  381. {
  382. rt_ubase_t level = rt_hw_interrupt_disable();
  383. rt_list_init(&traps->list);
  384. traps->data = data;
  385. traps->handler = handler;
  386. rt_list_insert_before(&_traps_nodes, &traps->list);
  387. err = RT_EOK;
  388. rt_hw_interrupt_enable(level);
  389. }
  390. else
  391. {
  392. LOG_E("No memory to save '%p' handler", handler);
  393. err = -RT_ENOMEM;
  394. }
  395. }
  396. return err;
  397. }
  398. rt_err_t rt_pic_do_traps(void)
  399. {
  400. rt_err_t err = -RT_ERROR;
  401. struct irq_traps *traps;
  402. rt_list_for_each_entry(traps, &_traps_nodes, list)
  403. {
  404. if (traps->handler(traps->data))
  405. {
  406. err = RT_EOK;
  407. break;
  408. }
  409. }
  410. return err;
  411. }
  412. rt_err_t rt_pic_handle_isr(struct rt_pic_irq *pirq)
  413. {
  414. rt_err_t err = -RT_EEMPTY;
  415. rt_list_t *handler_nodes;
  416. struct rt_irq_desc *action;
  417. #ifdef RT_USING_PIC_STATISTICS
  418. struct timespec ts;
  419. rt_ubase_t irq_time_ns;
  420. rt_ubase_t current_irq_begin;
  421. #endif
  422. RT_ASSERT(pirq != RT_NULL);
  423. RT_ASSERT(pirq->pic != RT_NULL);
  424. #ifdef RT_USING_PIC_STATISTICS
  425. rt_ktime_boottime_get_ns(&ts);
  426. current_irq_begin = ts.tv_sec * (1000UL * 1000 * 1000) + ts.tv_nsec;
  427. #endif
  428. handler_nodes = &pirq->isr.list;
  429. action = &pirq->isr.action;
  430. if (!rt_list_isempty(&pirq->children_nodes))
  431. {
  432. struct rt_pic_irq *child;
  433. rt_list_for_each_entry(child, &pirq->children_nodes, list)
  434. {
  435. rt_pic_irq_ack(child->irq);
  436. err = rt_pic_handle_isr(child);
  437. rt_pic_irq_eoi(child->irq);
  438. }
  439. }
  440. if (action->handler)
  441. {
  442. action->handler(pirq->irq, action->param);
  443. #ifdef RT_USING_INTERRUPT_INFO
  444. action->counter++;
  445. #ifdef RT_USING_SMP
  446. action->cpu_counter[rt_hw_cpu_id()]++;
  447. #endif
  448. #endif
  449. if (!rt_list_isempty(handler_nodes))
  450. {
  451. struct rt_pic_isr *isr;
  452. rt_list_for_each_entry(isr, handler_nodes, list)
  453. {
  454. action = &isr->action;
  455. RT_ASSERT(action->handler != RT_NULL);
  456. action->handler(pirq->irq, action->param);
  457. #ifdef RT_USING_INTERRUPT_INFO
  458. action->counter++;
  459. #ifdef RT_USING_SMP
  460. action->cpu_counter[rt_hw_cpu_id()]++;
  461. #endif
  462. #endif
  463. }
  464. }
  465. err = RT_EOK;
  466. }
  467. #ifdef RT_USING_PIC_STATISTICS
  468. rt_ktime_boottime_get_ns(&ts);
  469. irq_time_ns = ts.tv_sec * (1000UL * 1000 * 1000) + ts.tv_nsec - current_irq_begin;
  470. pirq->stat.sum_irq_time_ns += irq_time_ns;
  471. if (irq_time_ns < pirq->stat.min_irq_time_ns || pirq->stat.min_irq_time_ns == 0)
  472. {
  473. pirq->stat.min_irq_time_ns = irq_time_ns;
  474. }
  475. if (irq_time_ns > pirq->stat.max_irq_time_ns)
  476. {
  477. pirq->stat.max_irq_time_ns = irq_time_ns;
  478. }
  479. #endif
  480. return err;
  481. }
  482. rt_weak rt_err_t rt_pic_user_extends(struct rt_pic *pic)
  483. {
  484. return -RT_ENOSYS;
  485. }
  486. rt_err_t rt_pic_irq_init(void)
  487. {
  488. rt_err_t err = RT_EOK;
  489. struct rt_pic *pic;
  490. rt_list_for_each_entry(pic, &_pic_nodes, list)
  491. {
  492. if (pic->ops->irq_init)
  493. {
  494. err = pic->ops->irq_init(pic);
  495. if (err)
  496. {
  497. LOG_E("PIC = %s init fail", pic->ops->name);
  498. break;
  499. }
  500. }
  501. }
  502. return err;
  503. }
  504. rt_err_t rt_pic_irq_finit(void)
  505. {
  506. rt_err_t err = RT_EOK;
  507. struct rt_pic *pic;
  508. rt_list_for_each_entry(pic, &_pic_nodes, list)
  509. {
  510. if (pic->ops->irq_finit)
  511. {
  512. err = pic->ops->irq_finit(pic);
  513. if (err)
  514. {
  515. LOG_E("PIC = %s finit fail", pic->ops->name);
  516. break;
  517. }
  518. }
  519. }
  520. return err;
  521. }
  522. void rt_pic_irq_enable(int irq)
  523. {
  524. struct rt_pic_irq *pirq = irq2pirq(irq);
  525. RT_ASSERT(pirq != RT_NULL);
  526. rt_hw_spin_lock(&pirq->rw_lock.lock);
  527. if (pirq->pic->ops->irq_enable)
  528. {
  529. pirq->pic->ops->irq_enable(pirq);
  530. }
  531. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  532. }
  533. void rt_pic_irq_disable(int irq)
  534. {
  535. struct rt_pic_irq *pirq = irq2pirq(irq);
  536. RT_ASSERT(pirq != RT_NULL);
  537. rt_hw_spin_lock(&pirq->rw_lock.lock);
  538. if (pirq->pic->ops->irq_disable)
  539. {
  540. pirq->pic->ops->irq_disable(pirq);
  541. }
  542. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  543. }
  544. void rt_pic_irq_ack(int irq)
  545. {
  546. struct rt_pic_irq *pirq = irq2pirq(irq);
  547. RT_ASSERT(pirq != RT_NULL);
  548. rt_hw_spin_lock(&pirq->rw_lock.lock);
  549. if (pirq->pic->ops->irq_ack)
  550. {
  551. pirq->pic->ops->irq_ack(pirq);
  552. }
  553. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  554. }
  555. void rt_pic_irq_mask(int irq)
  556. {
  557. struct rt_pic_irq *pirq = irq2pirq(irq);
  558. RT_ASSERT(pirq != RT_NULL);
  559. rt_hw_spin_lock(&pirq->rw_lock.lock);
  560. if (pirq->pic->ops->irq_mask)
  561. {
  562. pirq->pic->ops->irq_mask(pirq);
  563. }
  564. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  565. }
  566. void rt_pic_irq_unmask(int irq)
  567. {
  568. struct rt_pic_irq *pirq = irq2pirq(irq);
  569. RT_ASSERT(pirq != RT_NULL);
  570. rt_hw_spin_lock(&pirq->rw_lock.lock);
  571. if (pirq->pic->ops->irq_unmask)
  572. {
  573. pirq->pic->ops->irq_unmask(pirq);
  574. }
  575. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  576. }
  577. void rt_pic_irq_eoi(int irq)
  578. {
  579. struct rt_pic_irq *pirq = irq2pirq(irq);
  580. RT_ASSERT(pirq != RT_NULL);
  581. rt_hw_spin_lock(&pirq->rw_lock.lock);
  582. if (pirq->pic->ops->irq_eoi)
  583. {
  584. pirq->pic->ops->irq_eoi(pirq);
  585. }
  586. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  587. }
  588. rt_err_t rt_pic_irq_set_priority(int irq, rt_uint32_t priority)
  589. {
  590. rt_err_t err = -RT_EINVAL;
  591. struct rt_pic_irq *pirq = irq2pirq(irq);
  592. if (pirq)
  593. {
  594. rt_hw_spin_lock(&pirq->rw_lock.lock);
  595. if (pirq->pic->ops->irq_set_priority)
  596. {
  597. err = pirq->pic->ops->irq_set_priority(pirq, priority);
  598. if (!err)
  599. {
  600. pirq->priority = priority;
  601. }
  602. }
  603. else
  604. {
  605. err = -RT_ENOSYS;
  606. }
  607. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  608. }
  609. return err;
  610. }
  611. rt_uint32_t rt_pic_irq_get_priority(int irq)
  612. {
  613. rt_uint32_t priority = RT_UINT32_MAX;
  614. struct rt_pic_irq *pirq = irq2pirq(irq);
  615. if (pirq)
  616. {
  617. rt_hw_spin_lock(&pirq->rw_lock.lock);
  618. priority = pirq->priority;
  619. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  620. }
  621. return priority;
  622. }
  623. rt_err_t rt_pic_irq_set_affinity(int irq, rt_bitmap_t *affinity)
  624. {
  625. rt_err_t err = -RT_EINVAL;
  626. struct rt_pic_irq *pirq;
  627. if (affinity && (pirq = irq2pirq(irq)))
  628. {
  629. rt_hw_spin_lock(&pirq->rw_lock.lock);
  630. if (pirq->pic->ops->irq_set_affinity)
  631. {
  632. err = pirq->pic->ops->irq_set_affinity(pirq, affinity);
  633. if (!err)
  634. {
  635. rt_memcpy(pirq->affinity, affinity, sizeof(pirq->affinity));
  636. }
  637. }
  638. else
  639. {
  640. err = -RT_ENOSYS;
  641. }
  642. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  643. }
  644. return err;
  645. }
  646. rt_err_t rt_pic_irq_get_affinity(int irq, rt_bitmap_t *out_affinity)
  647. {
  648. rt_err_t err = -RT_EINVAL;
  649. struct rt_pic_irq *pirq;
  650. if (out_affinity && (pirq = irq2pirq(irq)))
  651. {
  652. rt_hw_spin_lock(&pirq->rw_lock.lock);
  653. rt_memcpy(out_affinity, pirq->affinity, sizeof(pirq->affinity));
  654. err = RT_EOK;
  655. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  656. }
  657. return err;
  658. }
  659. rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode)
  660. {
  661. rt_err_t err = -RT_EINVAL;
  662. struct rt_pic_irq *pirq;
  663. if ((~mode & RT_IRQ_MODE_MASK) && (pirq = irq2pirq(irq)))
  664. {
  665. rt_hw_spin_lock(&pirq->rw_lock.lock);
  666. if (pirq->pic->ops->irq_set_triger_mode)
  667. {
  668. err = pirq->pic->ops->irq_set_triger_mode(pirq, mode);
  669. if (!err)
  670. {
  671. pirq->mode = mode;
  672. }
  673. }
  674. else
  675. {
  676. err = -RT_ENOSYS;
  677. }
  678. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  679. }
  680. return err;
  681. }
  682. rt_uint32_t rt_pic_irq_get_triger_mode(int irq)
  683. {
  684. rt_uint32_t mode = RT_UINT32_MAX;
  685. struct rt_pic_irq *pirq = irq2pirq(irq);
  686. if (pirq)
  687. {
  688. rt_hw_spin_lock(&pirq->rw_lock.lock);
  689. mode = pirq->mode;
  690. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  691. }
  692. return mode;
  693. }
  694. void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask)
  695. {
  696. struct rt_pic_irq *pirq;
  697. if (cpumask && (pirq = irq2pirq(irq)))
  698. {
  699. rt_hw_spin_lock(&pirq->rw_lock.lock);
  700. if (pirq->pic->ops->irq_send_ipi)
  701. {
  702. pirq->pic->ops->irq_send_ipi(pirq, cpumask);
  703. }
  704. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  705. }
  706. }
  707. rt_err_t rt_pic_irq_set_state_raw(struct rt_pic *pic, int hwirq, int type, rt_bool_t state)
  708. {
  709. rt_err_t err;
  710. if (pic && hwirq >= 0)
  711. {
  712. if (pic->ops->irq_set_state)
  713. {
  714. err = pic->ops->irq_set_state(pic, hwirq, type, state);
  715. }
  716. else
  717. {
  718. err = -RT_ENOSYS;
  719. }
  720. }
  721. else
  722. {
  723. err = -RT_EINVAL;
  724. }
  725. return err;
  726. }
  727. rt_err_t rt_pic_irq_get_state_raw(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state)
  728. {
  729. rt_err_t err;
  730. if (pic && hwirq >= 0)
  731. {
  732. if (pic->ops->irq_get_state)
  733. {
  734. rt_bool_t state;
  735. if (!(err = pic->ops->irq_get_state(pic, hwirq, type, &state)) && out_state)
  736. {
  737. *out_state = state;
  738. }
  739. }
  740. else
  741. {
  742. err = -RT_ENOSYS;
  743. }
  744. }
  745. else
  746. {
  747. err = -RT_EINVAL;
  748. }
  749. return err;
  750. }
  751. rt_err_t rt_pic_irq_set_state(int irq, int type, rt_bool_t state)
  752. {
  753. rt_err_t err;
  754. struct rt_pic_irq *pirq = irq2pirq(irq);
  755. RT_ASSERT(pirq != RT_NULL);
  756. rt_hw_spin_lock(&pirq->rw_lock.lock);
  757. err = rt_pic_irq_set_state_raw(pirq->pic, pirq->hwirq, type, state);
  758. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  759. return err;
  760. }
  761. rt_err_t rt_pic_irq_get_state(int irq, int type, rt_bool_t *out_state)
  762. {
  763. rt_err_t err;
  764. struct rt_pic_irq *pirq = irq2pirq(irq);
  765. RT_ASSERT(pirq != RT_NULL);
  766. rt_hw_spin_lock(&pirq->rw_lock.lock);
  767. err = rt_pic_irq_get_state_raw(pirq->pic, pirq->hwirq, type, out_state);
  768. rt_hw_spin_unlock(&pirq->rw_lock.lock);
  769. return err;
  770. }
  771. void rt_pic_irq_parent_enable(struct rt_pic_irq *pirq)
  772. {
  773. RT_ASSERT(pirq != RT_NULL);
  774. pirq = pirq->parent;
  775. if (pirq->pic->ops->irq_enable)
  776. {
  777. pirq->pic->ops->irq_enable(pirq);
  778. }
  779. }
  780. void rt_pic_irq_parent_disable(struct rt_pic_irq *pirq)
  781. {
  782. RT_ASSERT(pirq != RT_NULL);
  783. pirq = pirq->parent;
  784. if (pirq->pic->ops->irq_disable)
  785. {
  786. pirq->pic->ops->irq_disable(pirq);
  787. }
  788. }
  789. void rt_pic_irq_parent_ack(struct rt_pic_irq *pirq)
  790. {
  791. RT_ASSERT(pirq != RT_NULL);
  792. pirq = pirq->parent;
  793. if (pirq->pic->ops->irq_ack)
  794. {
  795. pirq->pic->ops->irq_ack(pirq);
  796. }
  797. }
  798. void rt_pic_irq_parent_mask(struct rt_pic_irq *pirq)
  799. {
  800. RT_ASSERT(pirq != RT_NULL);
  801. pirq = pirq->parent;
  802. if (pirq->pic->ops->irq_mask)
  803. {
  804. pirq->pic->ops->irq_mask(pirq);
  805. }
  806. }
  807. void rt_pic_irq_parent_unmask(struct rt_pic_irq *pirq)
  808. {
  809. RT_ASSERT(pirq != RT_NULL);
  810. pirq = pirq->parent;
  811. if (pirq->pic->ops->irq_unmask)
  812. {
  813. pirq->pic->ops->irq_unmask(pirq);
  814. }
  815. }
  816. void rt_pic_irq_parent_eoi(struct rt_pic_irq *pirq)
  817. {
  818. RT_ASSERT(pirq != RT_NULL);
  819. pirq = pirq->parent;
  820. if (pirq->pic->ops->irq_eoi)
  821. {
  822. pirq->pic->ops->irq_eoi(pirq);
  823. }
  824. }
  825. rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic_irq *pirq, rt_uint32_t priority)
  826. {
  827. rt_err_t err = -RT_ENOSYS;
  828. RT_ASSERT(pirq != RT_NULL);
  829. pirq = pirq->parent;
  830. if (pirq->pic->ops->irq_set_priority)
  831. {
  832. if (!(err = pirq->pic->ops->irq_set_priority(pirq, priority)))
  833. {
  834. pirq->priority = priority;
  835. }
  836. }
  837. return err;
  838. }
  839. rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic_irq *pirq, rt_bitmap_t *affinity)
  840. {
  841. rt_err_t err = -RT_ENOSYS;
  842. RT_ASSERT(pirq != RT_NULL);
  843. pirq = pirq->parent;
  844. if (pirq->pic->ops->irq_set_affinity)
  845. {
  846. if (!(err = pirq->pic->ops->irq_set_affinity(pirq, affinity)))
  847. {
  848. rt_memcpy(pirq->affinity, affinity, sizeof(pirq->affinity));
  849. }
  850. }
  851. return err;
  852. }
  853. rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode)
  854. {
  855. rt_err_t err = -RT_ENOSYS;
  856. RT_ASSERT(pirq != RT_NULL);
  857. pirq = pirq->parent;
  858. if (pirq->pic->ops->irq_set_triger_mode)
  859. {
  860. if (!(err = pirq->pic->ops->irq_set_triger_mode(pirq, mode)))
  861. {
  862. pirq->mode = mode;
  863. }
  864. }
  865. return err;
  866. }
  867. #ifdef RT_USING_OFW
  868. RT_OFW_STUB_RANGE_EXPORT(pic, _pic_ofw_start, _pic_ofw_end);
  869. static rt_err_t ofw_pic_init(void)
  870. {
  871. struct rt_ofw_node *ic_np;
  872. rt_ofw_foreach_node_by_prop(ic_np, "interrupt-controller")
  873. {
  874. rt_ofw_stub_probe_range(ic_np, &_pic_ofw_start, &_pic_ofw_end);
  875. }
  876. return RT_EOK;
  877. }
  878. #else
  879. static rt_err_t ofw_pic_init(void)
  880. {
  881. return RT_EOK;
  882. }
  883. #endif /* !RT_USING_OFW */
  884. rt_err_t rt_pic_init(void)
  885. {
  886. rt_err_t err;
  887. LOG_D("init start");
  888. err = ofw_pic_init();
  889. LOG_D("init end");
  890. return err;
  891. }
  892. #if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
  893. static int list_irq(int argc, char**argv)
  894. {
  895. rt_size_t irq_nr = 0;
  896. rt_bool_t dump_all = RT_FALSE;
  897. const char *const irq_modes[] =
  898. {
  899. [RT_IRQ_MODE_NONE] = "None",
  900. [RT_IRQ_MODE_EDGE_RISING] = "Edge-Rising",
  901. [RT_IRQ_MODE_EDGE_FALLING] = "Edge-Falling",
  902. [RT_IRQ_MODE_EDGE_BOTH] = "Edge-Both",
  903. [RT_IRQ_MODE_LEVEL_HIGH] = "Level-High",
  904. [RT_IRQ_MODE_LEVEL_LOW] = "Level-Low",
  905. };
  906. static char info[RT_CONSOLEBUF_SIZE];
  907. #ifdef RT_USING_SMP
  908. static char cpumask[RT_CPUS_NR + 1] = { [RT_CPUS_NR] = '\0' };
  909. #endif
  910. if (argc > 1)
  911. {
  912. if (!rt_strcmp(argv[1], "all"))
  913. {
  914. dump_all = RT_TRUE;
  915. }
  916. }
  917. rt_kprintf("%-*.s %-*.s %s %-*.s %-*.s %-*.s %-*.sUsers%-*.s",
  918. 6, "IRQ",
  919. 6, "HW-IRQ",
  920. "MSI",
  921. _pic_name_max, "PIC",
  922. 12, "Mode",
  923. #ifdef RT_USING_SMP
  924. RT_CPUS_NR, "CPUs",
  925. #else
  926. 0, 0,
  927. #endif
  928. #ifdef RT_USING_INTERRUPT_INFO
  929. 11, "Count",
  930. 5, ""
  931. #else
  932. 0, 0,
  933. 10, "-Number"
  934. #endif
  935. );
  936. #if defined(RT_USING_SMP) && defined(RT_USING_INTERRUPT_INFO)
  937. for (int i = 0; i < RT_CPUS_NR; i++)
  938. {
  939. rt_kprintf(" cpu%2d ", i);
  940. }
  941. #endif
  942. #ifdef RT_USING_PIC_STATISTICS
  943. rt_kprintf(" max/ns avg/ns min/ns");
  944. #endif
  945. rt_kputs("\n");
  946. for (int i = 0; i < RT_ARRAY_SIZE(_pirq_hash); ++i)
  947. {
  948. struct rt_pic_irq *pirq = &_pirq_hash[i];
  949. if (!pirq->pic || !(dump_all || pirq->isr.action.handler))
  950. {
  951. continue;
  952. }
  953. rt_snprintf(info, sizeof(info), "%-6d %-6d %c %-*.s %-*.s ",
  954. pirq->irq,
  955. pirq->hwirq,
  956. pirq->msi_desc ? 'Y' : 'N',
  957. _pic_name_max, pirq->pic->ops->name,
  958. 12, irq_modes[pirq->mode]);
  959. #ifdef RT_USING_SMP
  960. for (int group = 0, id = 0; group < RT_ARRAY_SIZE(pirq->affinity); ++group)
  961. {
  962. rt_bitmap_t mask = pirq->affinity[group];
  963. for (int idx = 0; id < RT_CPUS_NR && idx < RT_BITMAP_BIT_LEN(1); ++idx, ++id)
  964. {
  965. cpumask[RT_ARRAY_SIZE(cpumask) - id - 2] = '0' + ((mask >> idx) & 1);
  966. }
  967. }
  968. #endif /* RT_USING_SMP */
  969. rt_kputs(info);
  970. #ifdef RT_USING_SMP
  971. rt_kputs(cpumask);
  972. #endif
  973. #ifdef RT_USING_INTERRUPT_INFO
  974. rt_kprintf(" %-10d ", pirq->isr.action.counter);
  975. rt_kprintf("%-*.s", 10, pirq->isr.action.name);
  976. #ifdef RT_USING_SMP
  977. for (int cpuid = 0; cpuid < RT_CPUS_NR; cpuid++)
  978. {
  979. rt_kprintf(" %-10d", pirq->isr.action.cpu_counter[cpuid]);
  980. }
  981. #endif
  982. #ifdef RT_USING_PIC_STATISTICS
  983. rt_kprintf(" %-10d %-10d %-10d", pirq->stat.max_irq_time_ns, pirq->stat.sum_irq_time_ns/pirq->isr.action.counter, pirq->stat.min_irq_time_ns);
  984. #endif
  985. rt_kputs("\n");
  986. if (!rt_list_isempty(&pirq->isr.list))
  987. {
  988. struct rt_pic_isr *repeat_isr;
  989. rt_list_for_each_entry(repeat_isr, &pirq->isr.list, list)
  990. {
  991. rt_kputs(info);
  992. #ifdef RT_USING_SMP
  993. rt_kputs(cpumask);
  994. #endif
  995. rt_kprintf("%-10d ", repeat_isr->action.counter);
  996. rt_kprintf("%-*.s", 10, repeat_isr->action.name);
  997. #ifdef RT_USING_SMP
  998. for (int cpuid = 0; cpuid < RT_CPUS_NR; cpuid++)
  999. {
  1000. rt_kprintf(" %-10d", repeat_isr->action.cpu_counter[cpuid]);
  1001. }
  1002. #endif
  1003. #ifdef RT_USING_PIC_STATISTICS
  1004. rt_kprintf(" --- --- ---");
  1005. #endif
  1006. rt_kputs("\n");
  1007. }
  1008. }
  1009. #else
  1010. rt_kprintf(" %d\n", rt_list_len(&pirq->isr.list));
  1011. #endif
  1012. ++irq_nr;
  1013. }
  1014. rt_kprintf("%d IRQs found\n", irq_nr);
  1015. return 0;
  1016. }
  1017. MSH_CMD_EXPORT(list_irq, dump using or args = all of irq information);
  1018. #endif /* RT_USING_CONSOLE && RT_USING_MSH */