]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/octeon/ethernet-rgmii.c
staging: octeon-ethernet: update boilerplate comments
[karo-tx-linux.git] / drivers / staging / octeon / ethernet-rgmii.c
1 /*
2  * This file is based on code from OCTEON SDK by Cavium Networks.
3  *
4  * Copyright (c) 2003-2007 Cavium Networks
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, Version 2, as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/netdevice.h>
13 #include <linux/interrupt.h>
14 #include <linux/phy.h>
15 #include <linux/ratelimit.h>
16 #include <net/dst.h>
17
18 #include <asm/octeon/octeon.h>
19
20 #include "ethernet-defines.h"
21 #include "octeon-ethernet.h"
22 #include "ethernet-util.h"
23 #include "ethernet-mdio.h"
24
25 #include <asm/octeon/cvmx-helper.h>
26
27 #include <asm/octeon/cvmx-ipd-defs.h>
28 #include <asm/octeon/cvmx-npi-defs.h>
29 #include <asm/octeon/cvmx-gmxx-defs.h>
30
31 static DEFINE_SPINLOCK(global_register_lock);
32
33 static int number_rgmii_ports;
34
35 static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
36 {
37         union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
38         union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
39         union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
40         int interface = INTERFACE(priv->port);
41         int index = INDEX(priv->port);
42
43         /* Set preamble checking. */
44         gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
45                                                                    interface));
46         gmxx_rxx_frm_ctl.s.pre_chk = enable;
47         cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
48                        gmxx_rxx_frm_ctl.u64);
49
50         /* Set FCS stripping. */
51         ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
52         if (enable)
53                 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
54         else
55                 ipd_sub_port_fcs.s.port_bit &=
56                                         0xffffffffull ^ (1ull << priv->port);
57         cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
58
59         /* Clear any error bits. */
60         gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
61                                                                    interface));
62         cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
63                        gmxx_rxx_int_reg.u64);
64 }
65
66 static void cvm_oct_rgmii_poll(struct net_device *dev)
67 {
68         struct octeon_ethernet *priv = netdev_priv(dev);
69         unsigned long flags = 0;
70         cvmx_helper_link_info_t link_info;
71         int use_global_register_lock = (priv->phydev == NULL);
72
73         BUG_ON(in_interrupt());
74         if (use_global_register_lock) {
75                 /*
76                  * Take the global register lock since we are going to
77                  * touch registers that affect more than one port.
78                  */
79                 spin_lock_irqsave(&global_register_lock, flags);
80         } else {
81                 mutex_lock(&priv->phydev->bus->mdio_lock);
82         }
83
84         link_info = cvmx_helper_link_get(priv->port);
85         if (link_info.u64 == priv->link_info) {
86                 if (link_info.s.speed == 10) {
87                         /*
88                          * Read the GMXX_RXX_INT_REG[PCTERR] bit and
89                          * see if we are getting preamble errors.
90                          */
91                         int interface = INTERFACE(priv->port);
92                         int index = INDEX(priv->port);
93                         union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
94
95                         gmxx_rxx_int_reg.u64 =
96                             cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
97                                           (index, interface));
98                         if (gmxx_rxx_int_reg.s.pcterr) {
99                                 /*
100                                  * We are getting preamble errors at
101                                  * 10Mbps.  Most likely the PHY is
102                                  * giving us packets with mis aligned
103                                  * preambles. In order to get these
104                                  * packets we need to disable preamble
105                                  * checking and do it in software.
106                                  */
107                                 cvm_oct_set_hw_preamble(priv, false);
108                                 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
109                                                    dev->name);
110                         }
111                 }
112
113                 if (use_global_register_lock)
114                         spin_unlock_irqrestore(&global_register_lock, flags);
115                 else
116                         mutex_unlock(&priv->phydev->bus->mdio_lock);
117                 return;
118         }
119
120         /* Since the 10Mbps preamble workaround is allowed we need to enable
121            preamble checking, FCS stripping, and clear error bits on
122            every speed change. If errors occur during 10Mbps operation
123            the above code will change this stuff */
124         cvm_oct_set_hw_preamble(priv, true);
125
126         if (priv->phydev == NULL) {
127                 link_info = cvmx_helper_link_autoconf(priv->port);
128                 priv->link_info = link_info.u64;
129         }
130
131         if (use_global_register_lock)
132                 spin_unlock_irqrestore(&global_register_lock, flags);
133         else
134                 mutex_unlock(&priv->phydev->bus->mdio_lock);
135
136         if (priv->phydev == NULL) {
137                 /* Tell core. */
138                 if (link_info.s.link_up) {
139                         if (!netif_carrier_ok(dev))
140                                 netif_carrier_on(dev);
141                 } else if (netif_carrier_ok(dev)) {
142                         netif_carrier_off(dev);
143                 }
144                 cvm_oct_note_carrier(priv, link_info);
145         }
146 }
147
148 static int cmv_oct_rgmii_gmx_interrupt(int interface)
149 {
150         int index;
151         int count = 0;
152
153         /* Loop through every port of this interface */
154         for (index = 0;
155              index < cvmx_helper_ports_on_interface(interface);
156              index++) {
157                 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
158
159                 /* Read the GMX interrupt status bits */
160                 gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
161                                           (index, interface));
162                 gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
163                                           (index, interface));
164
165                 /* Poll the port if inband status changed */
166                 if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link ||
167                     gmx_rx_int_reg.s.phy_spd) {
168                         struct net_device *dev =
169                                     cvm_oct_device[cvmx_helper_get_ipd_port
170                                                    (interface, index)];
171                         struct octeon_ethernet *priv = netdev_priv(dev);
172
173                         if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
174                                 queue_work(cvm_oct_poll_queue,
175                                            &priv->port_work);
176
177                         gmx_rx_int_reg.u64 = 0;
178                         gmx_rx_int_reg.s.phy_dupx = 1;
179                         gmx_rx_int_reg.s.phy_link = 1;
180                         gmx_rx_int_reg.s.phy_spd = 1;
181                         cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
182                                        gmx_rx_int_reg.u64);
183                         count++;
184                 }
185         }
186         return count;
187 }
188
189 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
190 {
191         union cvmx_npi_rsl_int_blocks rsl_int_blocks;
192         int count = 0;
193
194         rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
195
196         /* Check and see if this interrupt was caused by the GMX0 block */
197         if (rsl_int_blocks.s.gmx0)
198                 count += cmv_oct_rgmii_gmx_interrupt(0);
199
200         /* Check and see if this interrupt was caused by the GMX1 block */
201         if (rsl_int_blocks.s.gmx1)
202                 count += cmv_oct_rgmii_gmx_interrupt(1);
203
204         return count ? IRQ_HANDLED : IRQ_NONE;
205 }
206
207 int cvm_oct_rgmii_open(struct net_device *dev)
208 {
209         return cvm_oct_common_open(dev, cvm_oct_rgmii_poll, false);
210 }
211
212 static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
213 {
214         struct octeon_ethernet *priv =
215                 container_of(work, struct octeon_ethernet, port_work);
216         cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
217 }
218
219 int cvm_oct_rgmii_init(struct net_device *dev)
220 {
221         struct octeon_ethernet *priv = netdev_priv(dev);
222         int r;
223
224         cvm_oct_common_init(dev);
225         INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
226         /*
227          * Due to GMX errata in CN3XXX series chips, it is necessary
228          * to take the link down immediately when the PHY changes
229          * state. In order to do this we call the poll function every
230          * time the RGMII inband status changes.  This may cause
231          * problems if the PHY doesn't implement inband status
232          * properly.
233          */
234         if (number_rgmii_ports == 0) {
235                 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
236                                 IRQF_SHARED, "RGMII", &number_rgmii_ports);
237                 if (r != 0)
238                         return r;
239         }
240         number_rgmii_ports++;
241
242         /*
243          * Only true RGMII ports need to be polled. In GMII mode, port
244          * 0 is really a RGMII port.
245          */
246         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
247              && (priv->port == 0))
248             || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
249
250                 if (!octeon_is_simulation()) {
251
252                         union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
253                         int interface = INTERFACE(priv->port);
254                         int index = INDEX(priv->port);
255
256                         /*
257                          * Enable interrupts on inband status changes
258                          * for this port.
259                          */
260                         gmx_rx_int_en.u64 = 0;
261                         gmx_rx_int_en.s.phy_dupx = 1;
262                         gmx_rx_int_en.s.phy_link = 1;
263                         gmx_rx_int_en.s.phy_spd = 1;
264                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
265                                        gmx_rx_int_en.u64);
266                 }
267         }
268
269         return 0;
270 }
271
272 void cvm_oct_rgmii_uninit(struct net_device *dev)
273 {
274         struct octeon_ethernet *priv = netdev_priv(dev);
275
276         cvm_oct_common_uninit(dev);
277
278         /*
279          * Only true RGMII ports need to be polled. In GMII mode, port
280          * 0 is really a RGMII port.
281          */
282         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
283              && (priv->port == 0))
284             || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
285
286                 if (!octeon_is_simulation()) {
287
288                         union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
289                         int interface = INTERFACE(priv->port);
290                         int index = INDEX(priv->port);
291
292                         /*
293                          * Disable interrupts on inband status changes
294                          * for this port.
295                          */
296                         gmx_rx_int_en.u64 =
297                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
298                                           (index, interface));
299                         gmx_rx_int_en.s.phy_dupx = 0;
300                         gmx_rx_int_en.s.phy_link = 0;
301                         gmx_rx_int_en.s.phy_spd = 0;
302                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
303                                        gmx_rx_int_en.u64);
304                 }
305         }
306
307         /* Remove the interrupt handler when the last port is removed. */
308         number_rgmii_ports--;
309         if (number_rgmii_ports == 0)
310                 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
311         cancel_work_sync(&priv->port_work);
312 }