aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakahiroi Shimizu <tshimizu818@gmail.com>2012-03-07 17:16:27 -0500
committerDavid S. Miller <davem@davemloft.net>2012-03-09 16:55:38 -0500
commit1a0bdadb4e36abac63b0a9787f372aac30c11a9e (patch)
treef66477ebd3542f16738995a049b0f341ee0ab82e
parent863d08ece9bf11043541e8017cfbdd16b800fbe5 (diff)
net/pch_gbe: supports eg20t ptp clock
Supports EG20T ptp clock in the driver Changes e-mail address. Adds number. Signed-off-by: Takahiro Shimizu <tshimizu818@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Kconfig13
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h13
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c217
3 files changed, 240 insertions, 3 deletions
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
index 00bc4fc968c7..bce01641ee6b 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
@@ -20,3 +20,16 @@ config PCH_GBE
20 purpose use. 20 purpose use.
21 ML7223/ML7831 is companion chip for Intel Atom E6xx series. 21 ML7223/ML7831 is companion chip for Intel Atom E6xx series.
22 ML7223/ML7831 is completely compatible for Intel EG20T PCH. 22 ML7223/ML7831 is completely compatible for Intel EG20T PCH.
23
24if PCH_GBE
25
26config PCH_PTP
27 bool "PCH PTP clock support"
28 default n
29 depends on PTP_1588_CLOCK_PCH
30 ---help---
31 Say Y here if you want to use Precision Time Protocol (PTP) in the
32 driver. PTP is a method to precisely synchronize distributed clocks
33 over Ethernet networks.
34
35endif # PCH_GBE
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
index a09a07197eb5..dd14915f54bb 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
@@ -630,6 +630,9 @@ struct pch_gbe_adapter {
630 unsigned long tx_queue_len; 630 unsigned long tx_queue_len;
631 bool have_msi; 631 bool have_msi;
632 bool rx_stop_flag; 632 bool rx_stop_flag;
633 int hwts_tx_en;
634 int hwts_rx_en;
635 struct pci_dev *ptp_pdev;
633}; 636};
634 637
635extern const char pch_driver_version[]; 638extern const char pch_driver_version[];
@@ -648,6 +651,16 @@ extern void pch_gbe_free_tx_resources(struct pch_gbe_adapter *adapter,
648extern void pch_gbe_free_rx_resources(struct pch_gbe_adapter *adapter, 651extern void pch_gbe_free_rx_resources(struct pch_gbe_adapter *adapter,
649 struct pch_gbe_rx_ring *rx_ring); 652 struct pch_gbe_rx_ring *rx_ring);
650extern void pch_gbe_update_stats(struct pch_gbe_adapter *adapter); 653extern void pch_gbe_update_stats(struct pch_gbe_adapter *adapter);
654#ifdef CONFIG_PCH_PTP
655extern u32 pch_ch_control_read(struct pci_dev *pdev);
656extern void pch_ch_control_write(struct pci_dev *pdev, u32 val);
657extern u32 pch_ch_event_read(struct pci_dev *pdev);
658extern void pch_ch_event_write(struct pci_dev *pdev, u32 val);
659extern u32 pch_src_uuid_lo_read(struct pci_dev *pdev);
660extern u32 pch_src_uuid_hi_read(struct pci_dev *pdev);
661extern u64 pch_rx_snap_read(struct pci_dev *pdev);
662extern u64 pch_tx_snap_read(struct pci_dev *pdev);
663#endif
651 664
652/* pch_gbe_param.c */ 665/* pch_gbe_param.c */
653extern void pch_gbe_check_options(struct pch_gbe_adapter *adapter); 666extern void pch_gbe_check_options(struct pch_gbe_adapter *adapter);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 69a66545c8ae..8035e5ff6e06 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) 1999 - 2010 Intel Corporation. 2 * Copyright (C) 1999 - 2010 Intel Corporation.
3 * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. 3 * Copyright (C) 2010 - 2012 LAPIS SEMICONDUCTOR CO., LTD.
4 * 4 *
5 * This code was derived from the Intel e1000e Linux driver. 5 * This code was derived from the Intel e1000e Linux driver.
6 * 6 *
@@ -21,6 +21,10 @@
21#include "pch_gbe.h" 21#include "pch_gbe.h"
22#include "pch_gbe_api.h" 22#include "pch_gbe_api.h"
23#include <linux/module.h> 23#include <linux/module.h>
24#ifdef CONFIG_PCH_PTP
25#include <linux/net_tstamp.h>
26#include <linux/ptp_classify.h>
27#endif
24 28
25#define DRV_VERSION "1.00" 29#define DRV_VERSION "1.00"
26const char pch_driver_version[] = DRV_VERSION; 30const char pch_driver_version[] = DRV_VERSION;
@@ -95,12 +99,195 @@ const char pch_driver_version[] = DRV_VERSION;
95 99
96#define PCH_GBE_INT_DISABLE_ALL 0 100#define PCH_GBE_INT_DISABLE_ALL 0
97 101
102#ifdef CONFIG_PCH_PTP
103/* Macros for ieee1588 */
104#define TICKS_NS_SHIFT 5
105
106/* 0x40 Time Synchronization Channel Control Register Bits */
107#define MASTER_MODE (1<<0)
108#define SLAVE_MODE (0<<0)
109#define V2_MODE (1<<31)
110#define CAP_MODE0 (0<<16)
111#define CAP_MODE2 (1<<17)
112
113/* 0x44 Time Synchronization Channel Event Register Bits */
114#define TX_SNAPSHOT_LOCKED (1<<0)
115#define RX_SNAPSHOT_LOCKED (1<<1)
116#endif
117
98static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; 118static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
99 119
100static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg); 120static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
101static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg, 121static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
102 int data); 122 int data);
103 123
124#ifdef CONFIG_PCH_PTP
125static struct sock_filter ptp_filter[] = {
126 PTP_FILTER
127};
128
129static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
130{
131 u8 *data = skb->data;
132 unsigned int offset;
133 u16 *hi, *id;
134 u32 lo;
135
136 if ((sk_run_filter(skb, ptp_filter) != PTP_CLASS_V2_IPV4) &&
137 (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)) {
138 return 0;
139 }
140
141 offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
142
143 if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
144 return 0;
145
146 hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
147 id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
148
149 memcpy(&lo, &hi[1], sizeof(lo));
150
151 return (uid_hi == *hi &&
152 uid_lo == lo &&
153 seqid == *id);
154}
155
156static void pch_rx_timestamp(
157 struct pch_gbe_adapter *adapter, struct sk_buff *skb)
158{
159 struct skb_shared_hwtstamps *shhwtstamps;
160 struct pci_dev *pdev;
161 u64 ns;
162 u32 hi, lo, val;
163 u16 uid, seq;
164
165 if (!adapter->hwts_rx_en)
166 return;
167
168 /* Get ieee1588's dev information */
169 pdev = adapter->ptp_pdev;
170
171 val = pch_ch_event_read(pdev);
172
173 if (!(val & RX_SNAPSHOT_LOCKED))
174 return;
175
176 lo = pch_src_uuid_lo_read(pdev);
177 hi = pch_src_uuid_hi_read(pdev);
178
179 uid = hi & 0xffff;
180 seq = (hi >> 16) & 0xffff;
181
182 if (!pch_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
183 goto out;
184
185 ns = pch_rx_snap_read(pdev);
186 ns <<= TICKS_NS_SHIFT;
187
188 shhwtstamps = skb_hwtstamps(skb);
189 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
190 shhwtstamps->hwtstamp = ns_to_ktime(ns);
191out:
192 pch_ch_event_write(pdev, RX_SNAPSHOT_LOCKED);
193}
194
195static void pch_tx_timestamp(
196 struct pch_gbe_adapter *adapter, struct sk_buff *skb)
197{
198 struct skb_shared_hwtstamps shhwtstamps;
199 struct pci_dev *pdev;
200 struct skb_shared_info *shtx;
201 u64 ns;
202 u32 cnt, val;
203
204 shtx = skb_shinfo(skb);
205 if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && adapter->hwts_tx_en))
206 shtx->tx_flags |= SKBTX_IN_PROGRESS;
207 else
208 return;
209
210 /* Get ieee1588's dev information */
211 pdev = adapter->ptp_pdev;
212
213 /*
214 * This really stinks, but we have to poll for the Tx time stamp.
215 * Usually, the time stamp is ready after 4 to 6 microseconds.
216 */
217 for (cnt = 0; cnt < 100; cnt++) {
218 val = pch_ch_event_read(pdev);
219 if (val & TX_SNAPSHOT_LOCKED)
220 break;
221 udelay(1);
222 }
223 if (!(val & TX_SNAPSHOT_LOCKED)) {
224 shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
225 return;
226 }
227
228 ns = pch_tx_snap_read(pdev);
229 ns <<= TICKS_NS_SHIFT;
230
231 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
232 shhwtstamps.hwtstamp = ns_to_ktime(ns);
233 skb_tstamp_tx(skb, &shhwtstamps);
234
235 pch_ch_event_write(pdev, TX_SNAPSHOT_LOCKED);
236}
237
238static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
239{
240 struct hwtstamp_config cfg;
241 struct pch_gbe_adapter *adapter = netdev_priv(netdev);
242 struct pci_dev *pdev;
243
244 if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
245 return -EFAULT;
246
247 if (cfg.flags) /* reserved for future extensions */
248 return -EINVAL;
249
250 /* Get ieee1588's dev information */
251 pdev = adapter->ptp_pdev;
252
253 switch (cfg.tx_type) {
254 case HWTSTAMP_TX_OFF:
255 adapter->hwts_tx_en = 0;
256 break;
257 case HWTSTAMP_TX_ON:
258 adapter->hwts_tx_en = 1;
259 break;
260 default:
261 return -ERANGE;
262 }
263
264 switch (cfg.rx_filter) {
265 case HWTSTAMP_FILTER_NONE:
266 adapter->hwts_rx_en = 0;
267 break;
268 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
269 adapter->hwts_rx_en = 0;
270 pch_ch_control_write(pdev, (SLAVE_MODE | CAP_MODE0));
271 break;
272 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
273 adapter->hwts_rx_en = 1;
274 pch_ch_control_write(pdev, (MASTER_MODE | CAP_MODE0));
275 break;
276 case HWTSTAMP_FILTER_PTP_V2_EVENT:
277 adapter->hwts_rx_en = 1;
278 pch_ch_control_write(pdev, (V2_MODE | CAP_MODE2));
279 break;
280 default:
281 return -ERANGE;
282 }
283
284 /* Clear out any old time stamps. */
285 pch_ch_event_write(pdev, TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED);
286
287 return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
288}
289#endif
290
104inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw) 291inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw)
105{ 292{
106 iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD); 293 iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD);
@@ -1072,6 +1259,11 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
1072 iowrite32(tx_ring->dma + 1259 iowrite32(tx_ring->dma +
1073 (int)sizeof(struct pch_gbe_tx_desc) * ring_num, 1260 (int)sizeof(struct pch_gbe_tx_desc) * ring_num,
1074 &hw->reg->TX_DSC_SW_P); 1261 &hw->reg->TX_DSC_SW_P);
1262
1263#ifdef CONFIG_PCH_PTP
1264 pch_tx_timestamp(adapter, skb);
1265#endif
1266
1075 dev_kfree_skb_any(skb); 1267 dev_kfree_skb_any(skb);
1076} 1268}
1077 1269
@@ -1543,6 +1735,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
1543 adapter->stats.multicast++; 1735 adapter->stats.multicast++;
1544 /* Write meta date of skb */ 1736 /* Write meta date of skb */
1545 skb_put(skb, length); 1737 skb_put(skb, length);
1738
1739#ifdef CONFIG_PCH_PTP
1740 pch_rx_timestamp(adapter, skb);
1741#endif
1742
1546 skb->protocol = eth_type_trans(skb, netdev); 1743 skb->protocol = eth_type_trans(skb, netdev);
1547 if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) 1744 if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK)
1548 skb->ip_summed = CHECKSUM_NONE; 1745 skb->ip_summed = CHECKSUM_NONE;
@@ -2144,6 +2341,11 @@ static int pch_gbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
2144 2341
2145 pr_debug("cmd : 0x%04x\n", cmd); 2342 pr_debug("cmd : 0x%04x\n", cmd);
2146 2343
2344#ifdef CONFIG_PCH_PTP
2345 if (cmd == SIOCSHWTSTAMP)
2346 return hwtstamp_ioctl(netdev, ifr, cmd);
2347#endif
2348
2147 return generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL); 2349 return generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
2148} 2350}
2149 2351
@@ -2435,6 +2637,15 @@ static int pch_gbe_probe(struct pci_dev *pdev,
2435 goto err_free_netdev; 2637 goto err_free_netdev;
2436 } 2638 }
2437 2639
2640#ifdef CONFIG_PCH_PTP
2641 adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
2642 PCI_DEVFN(12, 4));
2643 if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
2644 pr_err("Bad ptp filter\n");
2645 return -EINVAL;
2646 }
2647#endif
2648
2438 netdev->netdev_ops = &pch_gbe_netdev_ops; 2649 netdev->netdev_ops = &pch_gbe_netdev_ops;
2439 netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD; 2650 netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
2440 netif_napi_add(netdev, &adapter->napi, 2651 netif_napi_add(netdev, &adapter->napi,
@@ -2499,7 +2710,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
2499 netif_carrier_off(netdev); 2710 netif_carrier_off(netdev);
2500 netif_stop_queue(netdev); 2711 netif_stop_queue(netdev);
2501 2712
2502 dev_dbg(&pdev->dev, "OKIsemi(R) PCH Network Connection\n"); 2713 dev_dbg(&pdev->dev, "PCH Network Connection\n");
2503 2714
2504 device_set_wakeup_enable(&pdev->dev, 1); 2715 device_set_wakeup_enable(&pdev->dev, 1);
2505 return 0; 2716 return 0;
@@ -2600,7 +2811,7 @@ module_init(pch_gbe_init_module);
2600module_exit(pch_gbe_exit_module); 2811module_exit(pch_gbe_exit_module);
2601 2812
2602MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver"); 2813MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
2603MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>"); 2814MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>");
2604MODULE_LICENSE("GPL"); 2815MODULE_LICENSE("GPL");
2605MODULE_VERSION(DRV_VERSION); 2816MODULE_VERSION(DRV_VERSION);
2606MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id); 2817MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);