000-enable-alx-wol.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. diff -Naur /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/ethtool.c linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/ethtool.c
  2. --- /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/ethtool.c 2014-10-05 21:23:04.000000000 +0200
  3. +++ linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/ethtool.c 2014-10-20 12:38:31.169848017 +0200
  4. @@ -299,6 +299,40 @@
  5. }
  6. }
  7. +static void alx_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
  8. +{
  9. + struct alx_priv *alx = netdev_priv(netdev);
  10. + struct alx_hw *hw = &alx->hw;
  11. +
  12. + wol->supported = WAKE_MAGIC | WAKE_PHY;
  13. + wol->wolopts = 0;
  14. +
  15. + if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
  16. + wol->wolopts |= WAKE_MAGIC;
  17. + if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY)
  18. + wol->wolopts |= WAKE_PHY;
  19. +}
  20. +
  21. +static int alx_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
  22. +{
  23. + struct alx_priv *alx = netdev_priv(netdev);
  24. + struct alx_hw *hw = &alx->hw;
  25. +
  26. + if (wol->wolopts & ~(WAKE_MAGIC | WAKE_PHY))
  27. + return -EOPNOTSUPP;
  28. +
  29. + hw->sleep_ctrl = 0;
  30. +
  31. + if (wol->wolopts & WAKE_MAGIC)
  32. + hw->sleep_ctrl |= ALX_SLEEP_WOL_MAGIC;
  33. + if (wol->wolopts & WAKE_PHY)
  34. + hw->sleep_ctrl |= ALX_SLEEP_WOL_PHY;
  35. +
  36. + device_set_wakeup_enable(&alx->hw.pdev->dev, hw->sleep_ctrl);
  37. +
  38. + return 0;
  39. +}
  40. +
  41. const struct ethtool_ops alx_ethtool_ops = {
  42. .get_settings = alx_get_settings,
  43. .set_settings = alx_set_settings,
  44. @@ -306,6 +340,8 @@
  45. .set_pauseparam = alx_set_pauseparam,
  46. .get_msglevel = alx_get_msglevel,
  47. .set_msglevel = alx_set_msglevel,
  48. + .get_wol = alx_get_wol,
  49. + .set_wol = alx_set_wol,
  50. .get_link = ethtool_op_get_link,
  51. .get_strings = alx_get_strings,
  52. .get_sset_count = alx_get_sset_count,
  53. diff -Naur /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.c linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.c
  54. --- /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.c 2014-10-05 21:23:04.000000000 +0200
  55. +++ linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.c 2014-10-20 12:38:31.170848034 +0200
  56. @@ -332,6 +332,16 @@
  57. alx_write_mem32(hw, ALX_STAD1, val);
  58. }
  59. +static void alx_enable_osc(struct alx_hw *hw)
  60. +{
  61. + u32 val;
  62. +
  63. + /* rising edge */
  64. + val = alx_read_mem32(hw, ALX_MISC);
  65. + alx_write_mem32(hw, ALX_MISC, val & ~ALX_MISC_INTNLOSC_OPEN);
  66. + alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
  67. +}
  68. +
  69. static void alx_reset_osc(struct alx_hw *hw, u8 rev)
  70. {
  71. u32 val, val2;
  72. @@ -848,6 +858,66 @@
  73. }
  74. }
  75. +
  76. +/* NOTE:
  77. + * 1. phy link must be established before calling this function
  78. + * 2. wol option (pattern,magic,link,etc.) is configed before call it.
  79. + */
  80. +int alx_pre_suspend(struct alx_hw *hw, int speed, u8 duplex)
  81. +{
  82. + u32 master, mac, phy, val;
  83. + int err = 0;
  84. +
  85. + master = alx_read_mem32(hw, ALX_MASTER);
  86. + master &= ~ALX_MASTER_PCLKSEL_SRDS;
  87. + mac = hw->rx_ctrl;
  88. + /* 10/100 half */
  89. + ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED, ALX_MAC_CTRL_SPEED_10_100);
  90. + mac &= ~(ALX_MAC_CTRL_FULLD | ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
  91. +
  92. + phy = alx_read_mem32(hw, ALX_PHY_CTRL);
  93. + phy &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_CLS);
  94. + phy |= ALX_PHY_CTRL_RST_ANALOG | ALX_PHY_CTRL_HIB_PULSE |
  95. + ALX_PHY_CTRL_HIB_EN;
  96. +
  97. + /* without any activity */
  98. + if (!(hw->sleep_ctrl & ALX_SLEEP_ACTIVE)) {
  99. + err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
  100. + if (err)
  101. + return err;
  102. + phy |= ALX_PHY_CTRL_IDDQ | ALX_PHY_CTRL_POWER_DOWN;
  103. + } else {
  104. + if (hw->sleep_ctrl & (ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_CIFS))
  105. + mac |= ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_BRD_EN;
  106. + if (hw->sleep_ctrl & ALX_SLEEP_CIFS)
  107. + mac |= ALX_MAC_CTRL_TX_EN;
  108. + if (duplex == DUPLEX_FULL)
  109. + mac |= ALX_MAC_CTRL_FULLD;
  110. + if (speed == SPEED_1000)
  111. + ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
  112. + ALX_MAC_CTRL_SPEED_1000);
  113. + phy |= ALX_PHY_CTRL_DSPRST_OUT;
  114. + err = alx_write_phy_ext(hw, ALX_MIIEXT_ANEG,
  115. + ALX_MIIEXT_S3DIG10,
  116. + ALX_MIIEXT_S3DIG10_SL);
  117. + if (err)
  118. + return err;
  119. + }
  120. +
  121. + alx_enable_osc(hw);
  122. + hw->rx_ctrl = mac;
  123. + alx_write_mem32(hw, ALX_MASTER, master);
  124. + alx_write_mem32(hw, ALX_MAC_CTRL, mac);
  125. + alx_write_mem32(hw, ALX_PHY_CTRL, phy);
  126. +
  127. + /* set val of PDLL D3PLLOFF */
  128. + val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
  129. + val |= ALX_PDLL_TRNS1_D3PLLOFF_EN;
  130. + alx_write_mem32(hw, ALX_PDLL_TRNS1, val);
  131. +
  132. + return 0;
  133. +}
  134. +
  135. bool alx_phy_configured(struct alx_hw *hw)
  136. {
  137. u32 cfg, hw_cfg;
  138. @@ -920,6 +990,26 @@
  139. return alx_read_phy_reg(hw, ALX_MII_ISR, &isr);
  140. }
  141. +int alx_config_wol(struct alx_hw *hw)
  142. +{
  143. + u32 wol = 0;
  144. + int err = 0;
  145. +
  146. + /* turn on magic packet event */
  147. + if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
  148. + wol |= ALX_WOL0_MAGIC_EN | ALX_WOL0_PME_MAGIC_EN;
  149. +
  150. + /* turn on link up event */
  151. + if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY) {
  152. + wol |= ALX_WOL0_LINK_EN | ALX_WOL0_PME_LINK;
  153. + /* only link up can wake up */
  154. + err = alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP);
  155. + }
  156. + alx_write_mem32(hw, ALX_WOL0, wol);
  157. +
  158. + return err;
  159. +}
  160. +
  161. void alx_disable_rss(struct alx_hw *hw)
  162. {
  163. u32 ctrl = alx_read_mem32(hw, ALX_RXQ0);
  164. @@ -1031,6 +1121,71 @@
  165. alx_write_mem32(hw, ALX_WRR, val);
  166. }
  167. +int alx_select_powersaving_speed(struct alx_hw *hw, int *speed, u8 *duplex)
  168. +{
  169. + int i, err;
  170. + u16 lpa;
  171. +
  172. + err = alx_read_phy_link(hw);
  173. + if (err)
  174. + return err;
  175. +
  176. + if (hw->link_speed == SPEED_UNKNOWN) {
  177. + *speed = SPEED_UNKNOWN;
  178. + *duplex = DUPLEX_UNKNOWN;
  179. + return 0;
  180. + }
  181. +
  182. + err = alx_read_phy_reg(hw, MII_LPA, &lpa);
  183. + if (err)
  184. + return err;
  185. +
  186. + if (!(lpa & LPA_LPACK)) {
  187. + *speed = hw->link_speed;
  188. + return 0;
  189. + }
  190. +
  191. + if (lpa & LPA_10FULL) {
  192. + *speed = SPEED_10;
  193. + *duplex = DUPLEX_FULL;
  194. + } else if (lpa & LPA_10HALF) {
  195. + *speed = SPEED_10;
  196. + *duplex = DUPLEX_HALF;
  197. + } else if (lpa & LPA_100FULL) {
  198. + *speed = SPEED_100;
  199. + *duplex = DUPLEX_FULL;
  200. + } else {
  201. + *speed = SPEED_100;
  202. + *duplex = DUPLEX_HALF;
  203. + }
  204. +
  205. + if (*speed == hw->link_speed && *duplex == hw->duplex)
  206. + return 0;
  207. + err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
  208. + if (err)
  209. + return err;
  210. + err = alx_setup_speed_duplex(hw, alx_speed_to_ethadv(*speed, *duplex) |
  211. + ADVERTISED_Autoneg, ALX_FC_ANEG |
  212. + ALX_FC_RX | ALX_FC_TX);
  213. + if (err)
  214. + return err;
  215. +
  216. + /* wait for linkup */
  217. + for (i = 0; i < ALX_MAX_SETUP_LNK_CYCLE; i++) {
  218. + msleep(100);
  219. +
  220. + err = alx_read_phy_link(hw);
  221. + if (err < 0)
  222. + return err;
  223. + if (hw->link_speed != SPEED_UNKNOWN)
  224. + break;
  225. + }
  226. + if (i == ALX_MAX_SETUP_LNK_CYCLE)
  227. + return -ETIMEDOUT;
  228. +
  229. + return 0;
  230. +}
  231. +
  232. bool alx_get_phy_info(struct alx_hw *hw)
  233. {
  234. u16 devs1, devs2;
  235. diff -Naur /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.h linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.h
  236. --- /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.h 2014-10-05 21:23:04.000000000 +0200
  237. +++ linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/hw.h 2014-10-20 12:38:31.170848034 +0200
  238. @@ -485,6 +485,8 @@
  239. u8 flowctrl;
  240. u32 adv_cfg;
  241. + u32 sleep_ctrl;
  242. +
  243. spinlock_t mdio_lock;
  244. struct mdio_if_info mdio;
  245. u16 phy_id[2];
  246. @@ -547,12 +549,14 @@
  247. void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en);
  248. int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl);
  249. void alx_post_phy_link(struct alx_hw *hw);
  250. +int alx_pre_suspend(struct alx_hw *hw, int speed, u8 duplex);
  251. int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data);
  252. int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data);
  253. int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata);
  254. int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data);
  255. int alx_read_phy_link(struct alx_hw *hw);
  256. int alx_clear_phy_intr(struct alx_hw *hw);
  257. +int alx_config_wol(struct alx_hw *hw);
  258. void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc);
  259. void alx_start_mac(struct alx_hw *hw);
  260. int alx_reset_mac(struct alx_hw *hw);
  261. @@ -560,6 +564,7 @@
  262. bool alx_phy_configured(struct alx_hw *hw);
  263. void alx_configure_basic(struct alx_hw *hw);
  264. void alx_disable_rss(struct alx_hw *hw);
  265. +int alx_select_powersaving_speed(struct alx_hw *hw, int *speed, u8 *duplex);
  266. bool alx_get_phy_info(struct alx_hw *hw);
  267. void alx_update_hw_stats(struct alx_hw *hw);
  268. diff -Naur /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/main.c linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/main.c
  269. --- /tmp/linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/main.c 2014-10-05 21:23:04.000000000 +0200
  270. +++ linux-3.17.1-gentoo-r1/drivers/net/ethernet/atheros/alx/main.c 2014-10-20 12:38:45.141083411 +0200
  271. @@ -51,7 +51,6 @@
  272. const char alx_drv_name[] = "alx";
  273. -
  274. static void alx_free_txbuf(struct alx_priv *alx, int entry)
  275. {
  276. struct alx_buffer *txb = &alx->txq.bufs[entry];
  277. @@ -706,6 +705,7 @@
  278. alx->rxbuf_size = ALIGN(ALX_RAW_MTU(hw->mtu), 8);
  279. alx->tx_ringsz = 256;
  280. alx->rx_ringsz = 512;
  281. + hw->sleep_ctrl = ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_WOL_PHY;
  282. hw->imt = 200;
  283. alx->int_mask = ALX_ISR_MISC;
  284. hw->dma_chnl = hw->max_dma_chnl;
  285. @@ -960,6 +960,66 @@
  286. return 0;
  287. }
  288. +static int __alx_shutdown(struct pci_dev *pdev, bool *wol_en)
  289. +{
  290. + struct alx_priv *alx = pci_get_drvdata(pdev);
  291. + struct net_device *netdev = alx->dev;
  292. + struct alx_hw *hw = &alx->hw;
  293. + int err, speed;
  294. + u8 duplex;
  295. +
  296. + netif_device_detach(netdev);
  297. +
  298. + if (netif_running(netdev))
  299. + __alx_stop(alx);
  300. +
  301. +#ifdef CONFIG_PM_SLEEP
  302. + err = pci_save_state(pdev);
  303. + if (err)
  304. + return err;
  305. +#endif
  306. +
  307. + err = alx_select_powersaving_speed(hw, &speed, &duplex);
  308. + if (err)
  309. + return err;
  310. + err = alx_clear_phy_intr(hw);
  311. + if (err)
  312. + return err;
  313. + err = alx_pre_suspend(hw, speed, duplex);
  314. + if (err)
  315. + return err;
  316. + err = alx_config_wol(hw);
  317. + if (err)
  318. + return err;
  319. +
  320. + *wol_en = false;
  321. + if (hw->sleep_ctrl & ALX_SLEEP_ACTIVE) {
  322. + netif_info(alx, wol, netdev,
  323. + "wol: ctrl=%X, speed=%X\n",
  324. + hw->sleep_ctrl, speed);
  325. + device_set_wakeup_enable(&pdev->dev, true);
  326. + *wol_en = true;
  327. + }
  328. +
  329. + pci_disable_device(pdev);
  330. +
  331. + return 0;
  332. +}
  333. +
  334. +static void alx_shutdown(struct pci_dev *pdev)
  335. +{
  336. + int err;
  337. + bool wol_en;
  338. +
  339. + err = __alx_shutdown(pdev, &wol_en);
  340. + if (!err) {
  341. + pci_wake_from_d3(pdev, wol_en);
  342. + pci_set_power_state(pdev, PCI_D3hot);
  343. + } else {
  344. + dev_err(&pdev->dev, "shutdown fail %d\n", err);
  345. + }
  346. +}
  347. +
  348. static void alx_link_check(struct work_struct *work)
  349. {
  350. struct alx_priv *alx;
  351. @@ -1377,6 +1437,8 @@
  352. goto out_unmap;
  353. }
  354. + device_set_wakeup_enable(&pdev->dev, hw->sleep_ctrl);
  355. +
  356. netdev_info(netdev,
  357. "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n",
  358. netdev->dev_addr);
  359. @@ -1420,12 +1482,22 @@
  360. static int alx_suspend(struct device *dev)
  361. {
  362. struct pci_dev *pdev = to_pci_dev(dev);
  363. - struct alx_priv *alx = pci_get_drvdata(pdev);
  364. + int err;
  365. + bool wol_en;
  366. +
  367. + err = __alx_shutdown(pdev, &wol_en);
  368. + if (err) {
  369. + dev_err(&pdev->dev, "shutdown fail in suspend %d\n", err);
  370. + return err;
  371. + }
  372. +
  373. + if (wol_en) {
  374. + pci_prepare_to_sleep(pdev);
  375. + } else {
  376. + pci_wake_from_d3(pdev, false);
  377. + pci_set_power_state(pdev, PCI_D3hot);
  378. + }
  379. - if (!netif_running(alx->dev))
  380. - return 0;
  381. - netif_device_detach(alx->dev);
  382. - __alx_stop(alx);
  383. return 0;
  384. }
  385. @@ -1433,20 +1505,46 @@
  386. {
  387. struct pci_dev *pdev = to_pci_dev(dev);
  388. struct alx_priv *alx = pci_get_drvdata(pdev);
  389. - struct alx_hw *hw = &alx->hw;
  390. -
  391. - alx_reset_phy(hw);
  392. + struct net_device *netdev = alx->dev;
  393. + struct alx_hw *hw = &alx->hw;
  394. + int err;
  395. +
  396. + pci_set_power_state(pdev, PCI_D0);
  397. + pci_restore_state(pdev);
  398. + pci_save_state(pdev);
  399. +
  400. + pci_enable_wake(pdev, PCI_D3hot, 0);
  401. + pci_enable_wake(pdev, PCI_D3cold, 0);
  402. +
  403. + hw->link_speed = SPEED_UNKNOWN;
  404. + alx->int_mask = ALX_ISR_MISC;
  405. +
  406. + alx_reset_pcie(hw);
  407. + alx_reset_phy(hw);
  408. +
  409. + err = alx_reset_mac(hw);
  410. + if (err) {
  411. + netif_err(alx, hw, alx->dev,
  412. + "resume:reset_mac fail %d\n", err);
  413. + return -EIO;
  414. + }
  415. +
  416. + err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
  417. + if (err) {
  418. + netif_err(alx, hw, alx->dev,
  419. + "resume:setup_speed_duplex fail %d\n", err);
  420. + return -EIO;
  421. + }
  422. +
  423. + if (netif_running(netdev)) {
  424. + err = __alx_open(alx, true);
  425. + if (err)
  426. + return err;
  427. + }
  428. - if (!netif_running(alx->dev))
  429. - return 0;
  430. - netif_device_attach(alx->dev);
  431. - return __alx_open(alx, true);
  432. + netif_device_attach(netdev);
  433. + return err;
  434. }
  435. -
  436. -static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
  437. -#define ALX_PM_OPS (&alx_pm_ops)
  438. -#else
  439. -#define ALX_PM_OPS NULL
  440. #endif
  441. @@ -1492,6 +1590,8 @@
  442. }
  443. pci_set_master(pdev);
  444. + pci_enable_wake(pdev, PCI_D3hot, 0);
  445. + pci_enable_wake(pdev, PCI_D3cold, 0);
  446. alx_reset_pcie(hw);
  447. if (!alx_reset_mac(hw))
  448. @@ -1539,11 +1639,19 @@
  449. {}
  450. };
  451. +#ifdef CONFIG_PM_SLEEP
  452. +static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
  453. +#define ALX_PM_OPS (&alx_pm_ops)
  454. +#else
  455. +#define ALX_PM_OPS NULL
  456. +#endif
  457. +
  458. static struct pci_driver alx_driver = {
  459. .name = alx_drv_name,
  460. .id_table = alx_pci_tbl,
  461. .probe = alx_probe,
  462. .remove = alx_remove,
  463. + .shutdown = alx_shutdown,
  464. .err_handler = &alx_err_handlers,
  465. .driver.pm = ALX_PM_OPS,
  466. };