global1_atu.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * Marvell 88E6xxx Address Translation Unit (ATU) support
  3. *
  4. * Copyright (c) 2008 Marvell Semiconductor
  5. * Copyright (c) 2017 Savoir-faire Linux, Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. */
  12. #include "mv88e6xxx.h"
  13. #include "global1.h"
  14. /* Offset 0x01: ATU FID Register */
  15. static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid)
  16. {
  17. return mv88e6xxx_g1_write(chip, GLOBAL_ATU_FID, fid & 0xfff);
  18. }
  19. /* Offset 0x0A: ATU Control Register */
  20. int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all)
  21. {
  22. u16 val;
  23. int err;
  24. err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
  25. if (err)
  26. return err;
  27. if (learn2all)
  28. val |= GLOBAL_ATU_CONTROL_LEARN2ALL;
  29. else
  30. val &= ~GLOBAL_ATU_CONTROL_LEARN2ALL;
  31. return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
  32. }
  33. int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,
  34. unsigned int msecs)
  35. {
  36. const unsigned int coeff = chip->info->age_time_coeff;
  37. const unsigned int min = 0x01 * coeff;
  38. const unsigned int max = 0xff * coeff;
  39. u8 age_time;
  40. u16 val;
  41. int err;
  42. if (msecs < min || msecs > max)
  43. return -ERANGE;
  44. /* Round to nearest multiple of coeff */
  45. age_time = (msecs + coeff / 2) / coeff;
  46. err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
  47. if (err)
  48. return err;
  49. /* AgeTime is 11:4 bits */
  50. val &= ~0xff0;
  51. val |= age_time << 4;
  52. err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
  53. if (err)
  54. return err;
  55. dev_dbg(chip->dev, "AgeTime set to 0x%02x (%d ms)\n", age_time,
  56. age_time * coeff);
  57. return 0;
  58. }
  59. /* Offset 0x0B: ATU Operation Register */
  60. static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
  61. {
  62. return mv88e6xxx_g1_wait(chip, GLOBAL_ATU_OP, GLOBAL_ATU_OP_BUSY);
  63. }
  64. static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
  65. {
  66. u16 val;
  67. int err;
  68. /* FID bits are dispatched all around gradually as more are supported */
  69. if (mv88e6xxx_num_databases(chip) > 256) {
  70. err = mv88e6xxx_g1_atu_fid_write(chip, fid);
  71. if (err)
  72. return err;
  73. } else {
  74. if (mv88e6xxx_num_databases(chip) > 16) {
  75. /* ATU DBNum[7:4] are located in ATU Control 15:12 */
  76. err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
  77. if (err)
  78. return err;
  79. val = (val & 0x0fff) | ((fid << 8) & 0xf000);
  80. err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
  81. if (err)
  82. return err;
  83. }
  84. /* ATU DBNum[3:0] are located in ATU Operation 3:0 */
  85. op |= fid & 0xf;
  86. }
  87. err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_OP, op);
  88. if (err)
  89. return err;
  90. return mv88e6xxx_g1_atu_op_wait(chip);
  91. }
  92. /* Offset 0x0C: ATU Data Register */
  93. static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
  94. struct mv88e6xxx_atu_entry *entry)
  95. {
  96. u16 val;
  97. int err;
  98. err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_DATA, &val);
  99. if (err)
  100. return err;
  101. entry->state = val & 0xf;
  102. if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
  103. entry->trunk = !!(val & GLOBAL_ATU_DATA_TRUNK);
  104. entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
  105. }
  106. return 0;
  107. }
  108. static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
  109. struct mv88e6xxx_atu_entry *entry)
  110. {
  111. u16 data = entry->state & 0xf;
  112. if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
  113. if (entry->trunk)
  114. data |= GLOBAL_ATU_DATA_TRUNK;
  115. data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4;
  116. }
  117. return mv88e6xxx_g1_write(chip, GLOBAL_ATU_DATA, data);
  118. }
  119. /* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1
  120. * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3
  121. * Offset 0x0F: ATU MAC Address Register Bytes 4 & 5
  122. */
  123. static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip,
  124. struct mv88e6xxx_atu_entry *entry)
  125. {
  126. u16 val;
  127. int i, err;
  128. for (i = 0; i < 3; i++) {
  129. err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_MAC_01 + i, &val);
  130. if (err)
  131. return err;
  132. entry->mac[i * 2] = val >> 8;
  133. entry->mac[i * 2 + 1] = val & 0xff;
  134. }
  135. return 0;
  136. }
  137. static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip,
  138. struct mv88e6xxx_atu_entry *entry)
  139. {
  140. u16 val;
  141. int i, err;
  142. for (i = 0; i < 3; i++) {
  143. val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1];
  144. err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_MAC_01 + i, val);
  145. if (err)
  146. return err;
  147. }
  148. return 0;
  149. }
  150. /* Address Translation Unit operations */
  151. int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
  152. struct mv88e6xxx_atu_entry *entry)
  153. {
  154. int err;
  155. err = mv88e6xxx_g1_atu_op_wait(chip);
  156. if (err)
  157. return err;
  158. /* Write the MAC address to iterate from only once */
  159. if (entry->state == GLOBAL_ATU_DATA_STATE_UNUSED) {
  160. err = mv88e6xxx_g1_atu_mac_write(chip, entry);
  161. if (err)
  162. return err;
  163. }
  164. err = mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
  165. if (err)
  166. return err;
  167. err = mv88e6xxx_g1_atu_data_read(chip, entry);
  168. if (err)
  169. return err;
  170. return mv88e6xxx_g1_atu_mac_read(chip, entry);
  171. }
  172. int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
  173. struct mv88e6xxx_atu_entry *entry)
  174. {
  175. int err;
  176. err = mv88e6xxx_g1_atu_op_wait(chip);
  177. if (err)
  178. return err;
  179. err = mv88e6xxx_g1_atu_mac_write(chip, entry);
  180. if (err)
  181. return err;
  182. err = mv88e6xxx_g1_atu_data_write(chip, entry);
  183. if (err)
  184. return err;
  185. return mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_LOAD_DB);
  186. }
  187. static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid,
  188. struct mv88e6xxx_atu_entry *entry,
  189. bool all)
  190. {
  191. u16 op;
  192. int err;
  193. err = mv88e6xxx_g1_atu_op_wait(chip);
  194. if (err)
  195. return err;
  196. err = mv88e6xxx_g1_atu_data_write(chip, entry);
  197. if (err)
  198. return err;
  199. /* Flush/Move all or non-static entries from all or a given database */
  200. if (all && fid)
  201. op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB;
  202. else if (fid)
  203. op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
  204. else if (all)
  205. op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL;
  206. else
  207. op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC;
  208. return mv88e6xxx_g1_atu_op(chip, fid, op);
  209. }
  210. int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all)
  211. {
  212. struct mv88e6xxx_atu_entry entry = {
  213. .state = 0, /* Null EntryState means Flush */
  214. };
  215. return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
  216. }
  217. static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid,
  218. int from_port, int to_port, bool all)
  219. {
  220. struct mv88e6xxx_atu_entry entry = { 0 };
  221. unsigned long mask;
  222. int shift;
  223. if (!chip->info->atu_move_port_mask)
  224. return -EOPNOTSUPP;
  225. mask = chip->info->atu_move_port_mask;
  226. shift = bitmap_weight(&mask, 16);
  227. entry.state = 0xf, /* Full EntryState means Move */
  228. entry.portvec = from_port & mask;
  229. entry.portvec |= (to_port & mask) << shift;
  230. return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
  231. }
  232. int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
  233. bool all)
  234. {
  235. int from_port = port;
  236. int to_port = chip->info->atu_move_port_mask;
  237. return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all);
  238. }