global1_atu.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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 "chip.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, MV88E6352_G1_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, MV88E6XXX_G1_ATU_CTL, &val);
  25. if (err)
  26. return err;
  27. if (learn2all)
  28. val |= MV88E6XXX_G1_ATU_CTL_LEARN2ALL;
  29. else
  30. val &= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL;
  31. return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, 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, MV88E6XXX_G1_ATU_CTL, &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, MV88E6XXX_G1_ATU_CTL, 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, MV88E6XXX_G1_ATU_OP,
  63. MV88E6XXX_G1_ATU_OP_BUSY);
  64. }
  65. static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
  66. {
  67. u16 val;
  68. int err;
  69. /* FID bits are dispatched all around gradually as more are supported */
  70. if (mv88e6xxx_num_databases(chip) > 256) {
  71. err = mv88e6xxx_g1_atu_fid_write(chip, fid);
  72. if (err)
  73. return err;
  74. } else {
  75. if (mv88e6xxx_num_databases(chip) > 16) {
  76. /* ATU DBNum[7:4] are located in ATU Control 15:12 */
  77. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL,
  78. &val);
  79. if (err)
  80. return err;
  81. val = (val & 0x0fff) | ((fid << 8) & 0xf000);
  82. err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL,
  83. val);
  84. if (err)
  85. return err;
  86. }
  87. /* ATU DBNum[3:0] are located in ATU Operation 3:0 */
  88. op |= fid & 0xf;
  89. }
  90. err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
  91. MV88E6XXX_G1_ATU_OP_BUSY | op);
  92. if (err)
  93. return err;
  94. return mv88e6xxx_g1_atu_op_wait(chip);
  95. }
  96. /* Offset 0x0C: ATU Data Register */
  97. static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
  98. struct mv88e6xxx_atu_entry *entry)
  99. {
  100. u16 val;
  101. int err;
  102. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &val);
  103. if (err)
  104. return err;
  105. entry->state = val & 0xf;
  106. if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
  107. entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK);
  108. entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
  109. }
  110. return 0;
  111. }
  112. static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
  113. struct mv88e6xxx_atu_entry *entry)
  114. {
  115. u16 data = entry->state & 0xf;
  116. if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
  117. if (entry->trunk)
  118. data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
  119. data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4;
  120. }
  121. return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data);
  122. }
  123. /* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1
  124. * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3
  125. * Offset 0x0F: ATU MAC Address Register Bytes 4 & 5
  126. */
  127. static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip,
  128. struct mv88e6xxx_atu_entry *entry)
  129. {
  130. u16 val;
  131. int i, err;
  132. for (i = 0; i < 3; i++) {
  133. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01 + i, &val);
  134. if (err)
  135. return err;
  136. entry->mac[i * 2] = val >> 8;
  137. entry->mac[i * 2 + 1] = val & 0xff;
  138. }
  139. return 0;
  140. }
  141. static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip,
  142. struct mv88e6xxx_atu_entry *entry)
  143. {
  144. u16 val;
  145. int i, err;
  146. for (i = 0; i < 3; i++) {
  147. val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1];
  148. err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_MAC01 + i, val);
  149. if (err)
  150. return err;
  151. }
  152. return 0;
  153. }
  154. /* Address Translation Unit operations */
  155. int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
  156. struct mv88e6xxx_atu_entry *entry)
  157. {
  158. int err;
  159. err = mv88e6xxx_g1_atu_op_wait(chip);
  160. if (err)
  161. return err;
  162. /* Write the MAC address to iterate from only once */
  163. if (entry->state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
  164. err = mv88e6xxx_g1_atu_mac_write(chip, entry);
  165. if (err)
  166. return err;
  167. }
  168. err = mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
  169. if (err)
  170. return err;
  171. err = mv88e6xxx_g1_atu_data_read(chip, entry);
  172. if (err)
  173. return err;
  174. return mv88e6xxx_g1_atu_mac_read(chip, entry);
  175. }
  176. int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
  177. struct mv88e6xxx_atu_entry *entry)
  178. {
  179. int err;
  180. err = mv88e6xxx_g1_atu_op_wait(chip);
  181. if (err)
  182. return err;
  183. err = mv88e6xxx_g1_atu_mac_write(chip, entry);
  184. if (err)
  185. return err;
  186. err = mv88e6xxx_g1_atu_data_write(chip, entry);
  187. if (err)
  188. return err;
  189. return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_LOAD_DB);
  190. }
  191. static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid,
  192. struct mv88e6xxx_atu_entry *entry,
  193. bool all)
  194. {
  195. u16 op;
  196. int err;
  197. err = mv88e6xxx_g1_atu_op_wait(chip);
  198. if (err)
  199. return err;
  200. err = mv88e6xxx_g1_atu_data_write(chip, entry);
  201. if (err)
  202. return err;
  203. /* Flush/Move all or non-static entries from all or a given database */
  204. if (all && fid)
  205. op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB;
  206. else if (fid)
  207. op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
  208. else if (all)
  209. op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL;
  210. else
  211. op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC;
  212. return mv88e6xxx_g1_atu_op(chip, fid, op);
  213. }
  214. int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all)
  215. {
  216. struct mv88e6xxx_atu_entry entry = {
  217. .state = 0, /* Null EntryState means Flush */
  218. };
  219. return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
  220. }
  221. static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid,
  222. int from_port, int to_port, bool all)
  223. {
  224. struct mv88e6xxx_atu_entry entry = { 0 };
  225. unsigned long mask;
  226. int shift;
  227. if (!chip->info->atu_move_port_mask)
  228. return -EOPNOTSUPP;
  229. mask = chip->info->atu_move_port_mask;
  230. shift = bitmap_weight(&mask, 16);
  231. entry.state = 0xf, /* Full EntryState means Move */
  232. entry.portvec = from_port & mask;
  233. entry.portvec |= (to_port & mask) << shift;
  234. return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
  235. }
  236. int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
  237. bool all)
  238. {
  239. int from_port = port;
  240. int to_port = chip->info->atu_move_port_mask;
  241. return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all);
  242. }