mv88e6xxx.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*
  2. * net/dsa/mv88e6xxx.c - Marvell 88e6xxx switch chip support
  3. * Copyright (c) 2008 Marvell Semiconductor
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/list.h>
  13. #include <linux/module.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/phy.h>
  16. #include <net/dsa.h>
  17. #include "mv88e6xxx.h"
  18. /* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
  19. * use all 32 SMI bus addresses on its SMI bus, and all switch registers
  20. * will be directly accessible on some {device address,register address}
  21. * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
  22. * will only respond to SMI transactions to that specific address, and
  23. * an indirect addressing mechanism needs to be used to access its
  24. * registers.
  25. */
  26. static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
  27. {
  28. int ret;
  29. int i;
  30. for (i = 0; i < 16; i++) {
  31. ret = mdiobus_read(bus, sw_addr, 0);
  32. if (ret < 0)
  33. return ret;
  34. if ((ret & 0x8000) == 0)
  35. return 0;
  36. }
  37. return -ETIMEDOUT;
  38. }
  39. int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
  40. {
  41. int ret;
  42. if (sw_addr == 0)
  43. return mdiobus_read(bus, addr, reg);
  44. /* Wait for the bus to become free. */
  45. ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
  46. if (ret < 0)
  47. return ret;
  48. /* Transmit the read command. */
  49. ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
  50. if (ret < 0)
  51. return ret;
  52. /* Wait for the read command to complete. */
  53. ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
  54. if (ret < 0)
  55. return ret;
  56. /* Read the data. */
  57. ret = mdiobus_read(bus, sw_addr, 1);
  58. if (ret < 0)
  59. return ret;
  60. return ret & 0xffff;
  61. }
  62. int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
  63. {
  64. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  65. struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
  66. int ret;
  67. if (bus == NULL)
  68. return -EINVAL;
  69. mutex_lock(&ps->smi_mutex);
  70. ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg);
  71. mutex_unlock(&ps->smi_mutex);
  72. if (ret < 0)
  73. return ret;
  74. dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
  75. addr, reg, ret);
  76. return ret;
  77. }
  78. int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
  79. int reg, u16 val)
  80. {
  81. int ret;
  82. if (sw_addr == 0)
  83. return mdiobus_write(bus, addr, reg, val);
  84. /* Wait for the bus to become free. */
  85. ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
  86. if (ret < 0)
  87. return ret;
  88. /* Transmit the data to write. */
  89. ret = mdiobus_write(bus, sw_addr, 1, val);
  90. if (ret < 0)
  91. return ret;
  92. /* Transmit the write command. */
  93. ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
  94. if (ret < 0)
  95. return ret;
  96. /* Wait for the write command to complete. */
  97. ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
  98. if (ret < 0)
  99. return ret;
  100. return 0;
  101. }
  102. int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
  103. {
  104. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  105. struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
  106. int ret;
  107. if (bus == NULL)
  108. return -EINVAL;
  109. dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
  110. addr, reg, val);
  111. mutex_lock(&ps->smi_mutex);
  112. ret = __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val);
  113. mutex_unlock(&ps->smi_mutex);
  114. return ret;
  115. }
  116. int mv88e6xxx_config_prio(struct dsa_switch *ds)
  117. {
  118. /* Configure the IP ToS mapping registers. */
  119. REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
  120. REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
  121. REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
  122. REG_WRITE(REG_GLOBAL, 0x13, 0x5555);
  123. REG_WRITE(REG_GLOBAL, 0x14, 0xaaaa);
  124. REG_WRITE(REG_GLOBAL, 0x15, 0xaaaa);
  125. REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
  126. REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
  127. /* Configure the IEEE 802.1p priority mapping register. */
  128. REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
  129. return 0;
  130. }
  131. int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
  132. {
  133. REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
  134. REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
  135. REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
  136. return 0;
  137. }
  138. int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
  139. {
  140. int i;
  141. int ret;
  142. for (i = 0; i < 6; i++) {
  143. int j;
  144. /* Write the MAC address byte. */
  145. REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
  146. /* Wait for the write to complete. */
  147. for (j = 0; j < 16; j++) {
  148. ret = REG_READ(REG_GLOBAL2, 0x0d);
  149. if ((ret & 0x8000) == 0)
  150. break;
  151. }
  152. if (j == 16)
  153. return -ETIMEDOUT;
  154. }
  155. return 0;
  156. }
  157. int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
  158. {
  159. if (addr >= 0)
  160. return mv88e6xxx_reg_read(ds, addr, regnum);
  161. return 0xffff;
  162. }
  163. int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
  164. {
  165. if (addr >= 0)
  166. return mv88e6xxx_reg_write(ds, addr, regnum, val);
  167. return 0;
  168. }
  169. #ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
  170. static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
  171. {
  172. int ret;
  173. unsigned long timeout;
  174. ret = REG_READ(REG_GLOBAL, 0x04);
  175. REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
  176. timeout = jiffies + 1 * HZ;
  177. while (time_before(jiffies, timeout)) {
  178. ret = REG_READ(REG_GLOBAL, 0x00);
  179. usleep_range(1000, 2000);
  180. if ((ret & 0xc000) != 0xc000)
  181. return 0;
  182. }
  183. return -ETIMEDOUT;
  184. }
  185. static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
  186. {
  187. int ret;
  188. unsigned long timeout;
  189. ret = REG_READ(REG_GLOBAL, 0x04);
  190. REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
  191. timeout = jiffies + 1 * HZ;
  192. while (time_before(jiffies, timeout)) {
  193. ret = REG_READ(REG_GLOBAL, 0x00);
  194. usleep_range(1000, 2000);
  195. if ((ret & 0xc000) == 0xc000)
  196. return 0;
  197. }
  198. return -ETIMEDOUT;
  199. }
  200. static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
  201. {
  202. struct mv88e6xxx_priv_state *ps;
  203. ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
  204. if (mutex_trylock(&ps->ppu_mutex)) {
  205. struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
  206. if (mv88e6xxx_ppu_enable(ds) == 0)
  207. ps->ppu_disabled = 0;
  208. mutex_unlock(&ps->ppu_mutex);
  209. }
  210. }
  211. static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
  212. {
  213. struct mv88e6xxx_priv_state *ps = (void *)_ps;
  214. schedule_work(&ps->ppu_work);
  215. }
  216. static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
  217. {
  218. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  219. int ret;
  220. mutex_lock(&ps->ppu_mutex);
  221. /* If the PHY polling unit is enabled, disable it so that
  222. * we can access the PHY registers. If it was already
  223. * disabled, cancel the timer that is going to re-enable
  224. * it.
  225. */
  226. if (!ps->ppu_disabled) {
  227. ret = mv88e6xxx_ppu_disable(ds);
  228. if (ret < 0) {
  229. mutex_unlock(&ps->ppu_mutex);
  230. return ret;
  231. }
  232. ps->ppu_disabled = 1;
  233. } else {
  234. del_timer(&ps->ppu_timer);
  235. ret = 0;
  236. }
  237. return ret;
  238. }
  239. static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
  240. {
  241. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  242. /* Schedule a timer to re-enable the PHY polling unit. */
  243. mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
  244. mutex_unlock(&ps->ppu_mutex);
  245. }
  246. void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
  247. {
  248. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  249. mutex_init(&ps->ppu_mutex);
  250. INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
  251. init_timer(&ps->ppu_timer);
  252. ps->ppu_timer.data = (unsigned long)ps;
  253. ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
  254. }
  255. int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
  256. {
  257. int ret;
  258. ret = mv88e6xxx_ppu_access_get(ds);
  259. if (ret >= 0) {
  260. ret = mv88e6xxx_reg_read(ds, addr, regnum);
  261. mv88e6xxx_ppu_access_put(ds);
  262. }
  263. return ret;
  264. }
  265. int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
  266. int regnum, u16 val)
  267. {
  268. int ret;
  269. ret = mv88e6xxx_ppu_access_get(ds);
  270. if (ret >= 0) {
  271. ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
  272. mv88e6xxx_ppu_access_put(ds);
  273. }
  274. return ret;
  275. }
  276. #endif
  277. void mv88e6xxx_poll_link(struct dsa_switch *ds)
  278. {
  279. int i;
  280. for (i = 0; i < DSA_MAX_PORTS; i++) {
  281. struct net_device *dev;
  282. int uninitialized_var(port_status);
  283. int link;
  284. int speed;
  285. int duplex;
  286. int fc;
  287. dev = ds->ports[i];
  288. if (dev == NULL)
  289. continue;
  290. link = 0;
  291. if (dev->flags & IFF_UP) {
  292. port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), 0x00);
  293. if (port_status < 0)
  294. continue;
  295. link = !!(port_status & 0x0800);
  296. }
  297. if (!link) {
  298. if (netif_carrier_ok(dev)) {
  299. netdev_info(dev, "link down\n");
  300. netif_carrier_off(dev);
  301. }
  302. continue;
  303. }
  304. switch (port_status & 0x0300) {
  305. case 0x0000:
  306. speed = 10;
  307. break;
  308. case 0x0100:
  309. speed = 100;
  310. break;
  311. case 0x0200:
  312. speed = 1000;
  313. break;
  314. default:
  315. speed = -1;
  316. break;
  317. }
  318. duplex = (port_status & 0x0400) ? 1 : 0;
  319. fc = (port_status & 0x8000) ? 1 : 0;
  320. if (!netif_carrier_ok(dev)) {
  321. netdev_info(dev,
  322. "link up, %d Mb/s, %s duplex, flow control %sabled\n",
  323. speed,
  324. duplex ? "full" : "half",
  325. fc ? "en" : "dis");
  326. netif_carrier_on(dev);
  327. }
  328. }
  329. }
  330. static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
  331. {
  332. int ret;
  333. int i;
  334. for (i = 0; i < 10; i++) {
  335. ret = REG_READ(REG_GLOBAL, 0x1d);
  336. if ((ret & 0x8000) == 0)
  337. return 0;
  338. }
  339. return -ETIMEDOUT;
  340. }
  341. static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
  342. {
  343. int ret;
  344. /* Snapshot the hardware statistics counters for this port. */
  345. REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
  346. /* Wait for the snapshotting to complete. */
  347. ret = mv88e6xxx_stats_wait(ds);
  348. if (ret < 0)
  349. return ret;
  350. return 0;
  351. }
  352. static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
  353. {
  354. u32 _val;
  355. int ret;
  356. *val = 0;
  357. ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x1d, 0xcc00 | stat);
  358. if (ret < 0)
  359. return;
  360. ret = mv88e6xxx_stats_wait(ds);
  361. if (ret < 0)
  362. return;
  363. ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1e);
  364. if (ret < 0)
  365. return;
  366. _val = ret << 16;
  367. ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1f);
  368. if (ret < 0)
  369. return;
  370. *val = _val | ret;
  371. }
  372. void mv88e6xxx_get_strings(struct dsa_switch *ds,
  373. int nr_stats, struct mv88e6xxx_hw_stat *stats,
  374. int port, uint8_t *data)
  375. {
  376. int i;
  377. for (i = 0; i < nr_stats; i++) {
  378. memcpy(data + i * ETH_GSTRING_LEN,
  379. stats[i].string, ETH_GSTRING_LEN);
  380. }
  381. }
  382. void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
  383. int nr_stats, struct mv88e6xxx_hw_stat *stats,
  384. int port, uint64_t *data)
  385. {
  386. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  387. int ret;
  388. int i;
  389. mutex_lock(&ps->stats_mutex);
  390. ret = mv88e6xxx_stats_snapshot(ds, port);
  391. if (ret < 0) {
  392. mutex_unlock(&ps->stats_mutex);
  393. return;
  394. }
  395. /* Read each of the counters. */
  396. for (i = 0; i < nr_stats; i++) {
  397. struct mv88e6xxx_hw_stat *s = stats + i;
  398. u32 low;
  399. u32 high = 0;
  400. if (s->reg >= 0x100) {
  401. int ret;
  402. ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
  403. s->reg - 0x100);
  404. if (ret < 0)
  405. goto error;
  406. low = ret;
  407. if (s->sizeof_stat == 4) {
  408. ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
  409. s->reg - 0x100 + 1);
  410. if (ret < 0)
  411. goto error;
  412. high = ret;
  413. }
  414. data[i] = (((u64)high) << 16) | low;
  415. continue;
  416. }
  417. mv88e6xxx_stats_read(ds, s->reg, &low);
  418. if (s->sizeof_stat == 8)
  419. mv88e6xxx_stats_read(ds, s->reg + 1, &high);
  420. data[i] = (((u64)high) << 32) | low;
  421. }
  422. error:
  423. mutex_unlock(&ps->stats_mutex);
  424. }
  425. int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
  426. {
  427. return 32 * sizeof(u16);
  428. }
  429. void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
  430. struct ethtool_regs *regs, void *_p)
  431. {
  432. u16 *p = _p;
  433. int i;
  434. regs->version = 0;
  435. memset(p, 0xff, 32 * sizeof(u16));
  436. for (i = 0; i < 32; i++) {
  437. int ret;
  438. ret = mv88e6xxx_reg_read(ds, REG_PORT(port), i);
  439. if (ret >= 0)
  440. p[i] = ret;
  441. }
  442. }
  443. #ifdef CONFIG_NET_DSA_HWMON
  444. int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
  445. {
  446. struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
  447. int ret;
  448. int val;
  449. *temp = 0;
  450. mutex_lock(&ps->phy_mutex);
  451. ret = mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
  452. if (ret < 0)
  453. goto error;
  454. /* Enable temperature sensor */
  455. ret = mv88e6xxx_phy_read(ds, 0x0, 0x1a);
  456. if (ret < 0)
  457. goto error;
  458. ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
  459. if (ret < 0)
  460. goto error;
  461. /* Wait for temperature to stabilize */
  462. usleep_range(10000, 12000);
  463. val = mv88e6xxx_phy_read(ds, 0x0, 0x1a);
  464. if (val < 0) {
  465. ret = val;
  466. goto error;
  467. }
  468. /* Disable temperature sensor */
  469. ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
  470. if (ret < 0)
  471. goto error;
  472. *temp = ((val & 0x1f) - 5) * 5;
  473. error:
  474. mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
  475. mutex_unlock(&ps->phy_mutex);
  476. return ret;
  477. }
  478. #endif /* CONFIG_NET_DSA_HWMON */
  479. static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
  480. {
  481. unsigned long timeout = jiffies + HZ / 10;
  482. while (time_before(jiffies, timeout)) {
  483. int ret;
  484. ret = REG_READ(reg, offset);
  485. if (!(ret & mask))
  486. return 0;
  487. usleep_range(1000, 2000);
  488. }
  489. return -ETIMEDOUT;
  490. }
  491. int mv88e6xxx_phy_wait(struct dsa_switch *ds)
  492. {
  493. return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x18, 0x8000);
  494. }
  495. int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
  496. {
  497. return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x0800);
  498. }
  499. int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
  500. {
  501. return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x8000);
  502. }
  503. int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum)
  504. {
  505. int ret;
  506. REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum);
  507. ret = mv88e6xxx_phy_wait(ds);
  508. if (ret < 0)
  509. return ret;
  510. return REG_READ(REG_GLOBAL2, 0x19);
  511. }
  512. int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
  513. u16 val)
  514. {
  515. REG_WRITE(REG_GLOBAL2, 0x19, val);
  516. REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum);
  517. return mv88e6xxx_phy_wait(ds);
  518. }
  519. int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
  520. {
  521. int reg;
  522. reg = mv88e6xxx_phy_read_indirect(ds, port, 16);
  523. if (reg < 0)
  524. return -EOPNOTSUPP;
  525. e->eee_enabled = !!(reg & 0x0200);
  526. e->tx_lpi_enabled = !!(reg & 0x0100);
  527. reg = REG_READ(REG_PORT(port), 0);
  528. e->eee_active = !!(reg & 0x0040);
  529. return 0;
  530. }
  531. static int mv88e6xxx_eee_enable_set(struct dsa_switch *ds, int port,
  532. bool eee_enabled, bool tx_lpi_enabled)
  533. {
  534. int reg, nreg;
  535. reg = mv88e6xxx_phy_read_indirect(ds, port, 16);
  536. if (reg < 0)
  537. return reg;
  538. nreg = reg & ~0x0300;
  539. if (eee_enabled)
  540. nreg |= 0x0200;
  541. if (tx_lpi_enabled)
  542. nreg |= 0x0100;
  543. if (nreg != reg)
  544. return mv88e6xxx_phy_write_indirect(ds, port, 16, nreg);
  545. return 0;
  546. }
  547. int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
  548. struct phy_device *phydev, struct ethtool_eee *e)
  549. {
  550. int ret;
  551. ret = mv88e6xxx_eee_enable_set(ds, port, e->eee_enabled,
  552. e->tx_lpi_enabled);
  553. if (ret)
  554. return -EOPNOTSUPP;
  555. return 0;
  556. }
  557. static int __init mv88e6xxx_init(void)
  558. {
  559. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
  560. register_switch_driver(&mv88e6131_switch_driver);
  561. #endif
  562. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
  563. register_switch_driver(&mv88e6123_61_65_switch_driver);
  564. #endif
  565. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
  566. register_switch_driver(&mv88e6352_switch_driver);
  567. #endif
  568. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
  569. register_switch_driver(&mv88e6171_switch_driver);
  570. #endif
  571. return 0;
  572. }
  573. module_init(mv88e6xxx_init);
  574. static void __exit mv88e6xxx_cleanup(void)
  575. {
  576. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
  577. unregister_switch_driver(&mv88e6171_switch_driver);
  578. #endif
  579. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
  580. unregister_switch_driver(&mv88e6123_61_65_switch_driver);
  581. #endif
  582. #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
  583. unregister_switch_driver(&mv88e6131_switch_driver);
  584. #endif
  585. }
  586. module_exit(mv88e6xxx_cleanup);
  587. MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
  588. MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
  589. MODULE_LICENSE("GPL");