global2.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. * Marvell 88E6xxx Switch Global 2 Registers support (device address
  3. * 0x1C)
  4. *
  5. * Copyright (c) 2008 Marvell Semiconductor
  6. *
  7. * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. */
  14. #include <linux/irqdomain.h>
  15. #include "mv88e6xxx.h"
  16. #include "global2.h"
  17. #define ADDR_GLOBAL2 0x1c
  18. static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
  19. {
  20. return mv88e6xxx_read(chip, ADDR_GLOBAL2, reg, val);
  21. }
  22. static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
  23. {
  24. return mv88e6xxx_write(chip, ADDR_GLOBAL2, reg, val);
  25. }
  26. static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
  27. {
  28. return mv88e6xxx_update(chip, ADDR_GLOBAL2, reg, update);
  29. }
  30. static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
  31. {
  32. return mv88e6xxx_wait(chip, ADDR_GLOBAL2, reg, mask);
  33. }
  34. /* Offset 0x02: Management Enable 2x */
  35. /* Offset 0x03: Management Enable 0x */
  36. int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
  37. {
  38. int err;
  39. /* Consider the frames with reserved multicast destination
  40. * addresses matching 01:80:c2:00:00:2x as MGMT.
  41. */
  42. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) {
  43. err = mv88e6xxx_g2_write(chip, GLOBAL2_MGMT_EN_2X, 0xffff);
  44. if (err)
  45. return err;
  46. }
  47. /* Consider the frames with reserved multicast destination
  48. * addresses matching 01:80:c2:00:00:0x as MGMT.
  49. */
  50. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X))
  51. return mv88e6xxx_g2_write(chip, GLOBAL2_MGMT_EN_0X, 0xffff);
  52. return 0;
  53. }
  54. /* Offset 0x06: Device Mapping Table register */
  55. static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip,
  56. int target, int port)
  57. {
  58. u16 val = (target << 8) | (port & 0xf);
  59. return mv88e6xxx_g2_update(chip, GLOBAL2_DEVICE_MAPPING, val);
  60. }
  61. static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip)
  62. {
  63. int target, port;
  64. int err;
  65. /* Initialize the routing port to the 32 possible target devices */
  66. for (target = 0; target < 32; ++target) {
  67. port = 0xf;
  68. if (target < DSA_MAX_SWITCHES) {
  69. port = chip->ds->rtable[target];
  70. if (port == DSA_RTABLE_NONE)
  71. port = 0xf;
  72. }
  73. err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
  74. if (err)
  75. break;
  76. }
  77. return err;
  78. }
  79. /* Offset 0x07: Trunk Mask Table register */
  80. static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
  81. bool hask, u16 mask)
  82. {
  83. const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
  84. u16 val = (num << 12) | (mask & port_mask);
  85. if (hask)
  86. val |= GLOBAL2_TRUNK_MASK_HASK;
  87. return mv88e6xxx_g2_update(chip, GLOBAL2_TRUNK_MASK, val);
  88. }
  89. /* Offset 0x08: Trunk Mapping Table register */
  90. static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
  91. u16 map)
  92. {
  93. const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
  94. u16 val = (id << 11) | (map & port_mask);
  95. return mv88e6xxx_g2_update(chip, GLOBAL2_TRUNK_MAPPING, val);
  96. }
  97. static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip)
  98. {
  99. const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
  100. int i, err;
  101. /* Clear all eight possible Trunk Mask vectors */
  102. for (i = 0; i < 8; ++i) {
  103. err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
  104. if (err)
  105. return err;
  106. }
  107. /* Clear all sixteen possible Trunk ID routing vectors */
  108. for (i = 0; i < 16; ++i) {
  109. err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
  110. if (err)
  111. return err;
  112. }
  113. return 0;
  114. }
  115. /* Offset 0x09: Ingress Rate Command register
  116. * Offset 0x0A: Ingress Rate Data register
  117. */
  118. static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip)
  119. {
  120. int port, err;
  121. /* Init all Ingress Rate Limit resources of all ports */
  122. for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) {
  123. /* XXX newer chips (like 88E6390) have different 2-bit ops */
  124. err = mv88e6xxx_g2_write(chip, GLOBAL2_IRL_CMD,
  125. GLOBAL2_IRL_CMD_OP_INIT_ALL |
  126. (port << 8));
  127. if (err)
  128. break;
  129. /* Wait for the operation to complete */
  130. err = mv88e6xxx_g2_wait(chip, GLOBAL2_IRL_CMD,
  131. GLOBAL2_IRL_CMD_BUSY);
  132. if (err)
  133. break;
  134. }
  135. return err;
  136. }
  137. /* Offset 0x0D: Switch MAC/WoL/WoF register */
  138. static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
  139. unsigned int pointer, u8 data)
  140. {
  141. u16 val = (pointer << 8) | data;
  142. return mv88e6xxx_g2_update(chip, GLOBAL2_SWITCH_MAC, val);
  143. }
  144. int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
  145. {
  146. int i, err;
  147. for (i = 0; i < 6; i++) {
  148. err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
  149. if (err)
  150. break;
  151. }
  152. return err;
  153. }
  154. /* Offset 0x0F: Priority Override Table */
  155. static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
  156. u8 data)
  157. {
  158. u16 val = (pointer << 8) | (data & 0x7);
  159. return mv88e6xxx_g2_update(chip, GLOBAL2_PRIO_OVERRIDE, val);
  160. }
  161. static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)
  162. {
  163. int i, err;
  164. /* Clear all sixteen possible Priority Override entries */
  165. for (i = 0; i < 16; i++) {
  166. err = mv88e6xxx_g2_pot_write(chip, i, 0);
  167. if (err)
  168. break;
  169. }
  170. return err;
  171. }
  172. /* Offset 0x14: EEPROM Command
  173. * Offset 0x15: EEPROM Data
  174. */
  175. static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
  176. {
  177. return mv88e6xxx_g2_wait(chip, GLOBAL2_EEPROM_CMD,
  178. GLOBAL2_EEPROM_CMD_BUSY |
  179. GLOBAL2_EEPROM_CMD_RUNNING);
  180. }
  181. static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
  182. {
  183. int err;
  184. err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_CMD, cmd);
  185. if (err)
  186. return err;
  187. return mv88e6xxx_g2_eeprom_wait(chip);
  188. }
  189. static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
  190. u8 addr, u16 *data)
  191. {
  192. u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ | addr;
  193. int err;
  194. err = mv88e6xxx_g2_eeprom_wait(chip);
  195. if (err)
  196. return err;
  197. err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
  198. if (err)
  199. return err;
  200. return mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_DATA, data);
  201. }
  202. static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
  203. u8 addr, u16 data)
  204. {
  205. u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | addr;
  206. int err;
  207. err = mv88e6xxx_g2_eeprom_wait(chip);
  208. if (err)
  209. return err;
  210. err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_DATA, data);
  211. if (err)
  212. return err;
  213. return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
  214. }
  215. int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
  216. struct ethtool_eeprom *eeprom, u8 *data)
  217. {
  218. unsigned int offset = eeprom->offset;
  219. unsigned int len = eeprom->len;
  220. u16 val;
  221. int err;
  222. eeprom->len = 0;
  223. if (offset & 1) {
  224. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  225. if (err)
  226. return err;
  227. *data++ = (val >> 8) & 0xff;
  228. offset++;
  229. len--;
  230. eeprom->len++;
  231. }
  232. while (len >= 2) {
  233. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  234. if (err)
  235. return err;
  236. *data++ = val & 0xff;
  237. *data++ = (val >> 8) & 0xff;
  238. offset += 2;
  239. len -= 2;
  240. eeprom->len += 2;
  241. }
  242. if (len) {
  243. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  244. if (err)
  245. return err;
  246. *data++ = val & 0xff;
  247. offset++;
  248. len--;
  249. eeprom->len++;
  250. }
  251. return 0;
  252. }
  253. int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
  254. struct ethtool_eeprom *eeprom, u8 *data)
  255. {
  256. unsigned int offset = eeprom->offset;
  257. unsigned int len = eeprom->len;
  258. u16 val;
  259. int err;
  260. /* Ensure the RO WriteEn bit is set */
  261. err = mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_CMD, &val);
  262. if (err)
  263. return err;
  264. if (!(val & GLOBAL2_EEPROM_CMD_WRITE_EN))
  265. return -EROFS;
  266. eeprom->len = 0;
  267. if (offset & 1) {
  268. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  269. if (err)
  270. return err;
  271. val = (*data++ << 8) | (val & 0xff);
  272. err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
  273. if (err)
  274. return err;
  275. offset++;
  276. len--;
  277. eeprom->len++;
  278. }
  279. while (len >= 2) {
  280. val = *data++;
  281. val |= *data++ << 8;
  282. err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
  283. if (err)
  284. return err;
  285. offset += 2;
  286. len -= 2;
  287. eeprom->len += 2;
  288. }
  289. if (len) {
  290. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  291. if (err)
  292. return err;
  293. val = (val & 0xff00) | *data++;
  294. err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
  295. if (err)
  296. return err;
  297. offset++;
  298. len--;
  299. eeprom->len++;
  300. }
  301. return 0;
  302. }
  303. /* Offset 0x18: SMI PHY Command Register
  304. * Offset 0x19: SMI PHY Data Register
  305. */
  306. static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
  307. {
  308. return mv88e6xxx_g2_wait(chip, GLOBAL2_SMI_PHY_CMD,
  309. GLOBAL2_SMI_PHY_CMD_BUSY);
  310. }
  311. static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
  312. {
  313. int err;
  314. err = mv88e6xxx_g2_write(chip, GLOBAL2_SMI_PHY_CMD, cmd);
  315. if (err)
  316. return err;
  317. return mv88e6xxx_g2_smi_phy_wait(chip);
  318. }
  319. int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, int addr, int reg,
  320. u16 *val)
  321. {
  322. u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA | (addr << 5) | reg;
  323. int err;
  324. err = mv88e6xxx_g2_smi_phy_wait(chip);
  325. if (err)
  326. return err;
  327. err = mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
  328. if (err)
  329. return err;
  330. return mv88e6xxx_g2_read(chip, GLOBAL2_SMI_PHY_DATA, val);
  331. }
  332. int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, int addr, int reg,
  333. u16 val)
  334. {
  335. u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA | (addr << 5) | reg;
  336. int err;
  337. err = mv88e6xxx_g2_smi_phy_wait(chip);
  338. if (err)
  339. return err;
  340. err = mv88e6xxx_g2_write(chip, GLOBAL2_SMI_PHY_DATA, val);
  341. if (err)
  342. return err;
  343. return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
  344. }
  345. static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
  346. {
  347. struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
  348. unsigned int n = d->hwirq;
  349. chip->g2_irq.masked |= (1 << n);
  350. }
  351. static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
  352. {
  353. struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
  354. unsigned int n = d->hwirq;
  355. chip->g2_irq.masked &= ~(1 << n);
  356. }
  357. static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
  358. {
  359. struct mv88e6xxx_chip *chip = dev_id;
  360. unsigned int nhandled = 0;
  361. unsigned int sub_irq;
  362. unsigned int n;
  363. int err;
  364. u16 reg;
  365. mutex_lock(&chip->reg_lock);
  366. err = mv88e6xxx_g2_read(chip, GLOBAL2_INT_SOURCE, &reg);
  367. mutex_unlock(&chip->reg_lock);
  368. if (err)
  369. goto out;
  370. for (n = 0; n < 16; ++n) {
  371. if (reg & (1 << n)) {
  372. sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
  373. handle_nested_irq(sub_irq);
  374. ++nhandled;
  375. }
  376. }
  377. out:
  378. return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
  379. }
  380. static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
  381. {
  382. struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
  383. mutex_lock(&chip->reg_lock);
  384. }
  385. static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
  386. {
  387. struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
  388. mv88e6xxx_g2_write(chip, GLOBAL2_INT_MASK, ~chip->g2_irq.masked);
  389. mutex_unlock(&chip->reg_lock);
  390. }
  391. static struct irq_chip mv88e6xxx_g2_irq_chip = {
  392. .name = "mv88e6xxx-g2",
  393. .irq_mask = mv88e6xxx_g2_irq_mask,
  394. .irq_unmask = mv88e6xxx_g2_irq_unmask,
  395. .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock,
  396. .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock,
  397. };
  398. static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
  399. unsigned int irq,
  400. irq_hw_number_t hwirq)
  401. {
  402. struct mv88e6xxx_chip *chip = d->host_data;
  403. irq_set_chip_data(irq, d->host_data);
  404. irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
  405. irq_set_noprobe(irq);
  406. return 0;
  407. }
  408. static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
  409. .map = mv88e6xxx_g2_irq_domain_map,
  410. .xlate = irq_domain_xlate_twocell,
  411. };
  412. void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
  413. {
  414. int irq, virq;
  415. free_irq(chip->device_irq, chip);
  416. irq_dispose_mapping(chip->device_irq);
  417. for (irq = 0; irq < 16; irq++) {
  418. virq = irq_find_mapping(chip->g2_irq.domain, irq);
  419. irq_dispose_mapping(virq);
  420. }
  421. irq_domain_remove(chip->g2_irq.domain);
  422. }
  423. int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
  424. {
  425. int err, irq, virq;
  426. if (!chip->dev->of_node)
  427. return -EINVAL;
  428. chip->g2_irq.domain = irq_domain_add_simple(
  429. chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
  430. if (!chip->g2_irq.domain)
  431. return -ENOMEM;
  432. for (irq = 0; irq < 16; irq++)
  433. irq_create_mapping(chip->g2_irq.domain, irq);
  434. chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
  435. chip->g2_irq.masked = ~0;
  436. chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
  437. GLOBAL_STATUS_IRQ_DEVICE);
  438. if (chip->device_irq < 0) {
  439. err = chip->device_irq;
  440. goto out;
  441. }
  442. err = request_threaded_irq(chip->device_irq, NULL,
  443. mv88e6xxx_g2_irq_thread_fn,
  444. IRQF_ONESHOT, "mv88e6xxx-g1", chip);
  445. if (err)
  446. goto out;
  447. return 0;
  448. out:
  449. for (irq = 0; irq < 16; irq++) {
  450. virq = irq_find_mapping(chip->g2_irq.domain, irq);
  451. irq_dispose_mapping(virq);
  452. }
  453. irq_domain_remove(chip->g2_irq.domain);
  454. return err;
  455. }
  456. int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
  457. {
  458. u16 reg;
  459. int err;
  460. /* Ignore removed tag data on doubly tagged packets, disable
  461. * flow control messages, force flow control priority to the
  462. * highest, and send all special multicast frames to the CPU
  463. * port at the highest priority.
  464. */
  465. reg = GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI | (0x7 << 4);
  466. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
  467. mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
  468. reg |= GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x7;
  469. err = mv88e6xxx_g2_write(chip, GLOBAL2_SWITCH_MGMT, reg);
  470. if (err)
  471. return err;
  472. /* Program the DSA routing table. */
  473. err = mv88e6xxx_g2_set_device_mapping(chip);
  474. if (err)
  475. return err;
  476. /* Clear all trunk masks and mapping. */
  477. err = mv88e6xxx_g2_clear_trunk(chip);
  478. if (err)
  479. return err;
  480. if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_IRL)) {
  481. /* Disable ingress rate limiting by resetting all per port
  482. * ingress rate limit resources to their initial state.
  483. */
  484. err = mv88e6xxx_g2_clear_irl(chip);
  485. if (err)
  486. return err;
  487. }
  488. if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_PVT)) {
  489. /* Initialize Cross-chip Port VLAN Table to reset defaults */
  490. err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR,
  491. GLOBAL2_PVT_ADDR_OP_INIT_ONES);
  492. if (err)
  493. return err;
  494. }
  495. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
  496. /* Clear the priority override table. */
  497. err = mv88e6xxx_g2_clear_pot(chip);
  498. if (err)
  499. return err;
  500. }
  501. return 0;
  502. }