diff options
24 files changed, 6513 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/samsung-sxgbe.txt b/Documentation/devicetree/bindings/net/samsung-sxgbe.txt new file mode 100644 index 000000000000..989f6c95cfd5 --- /dev/null +++ b/Documentation/devicetree/bindings/net/samsung-sxgbe.txt @@ -0,0 +1,52 @@ +* Samsung 10G Ethernet driver (SXGBE) + +Required properties: +- compatible: Should be "samsung,sxgbe-v2.0a" +- reg: Address and length of the register set for the device +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupts: Should contain the SXGBE interrupts + These interrupts are ordered by fixed and follows variable + trasmit DMA interrupts, receive DMA interrupts and lpi interrupt. + index 0 - this is fixed common interrupt of SXGBE and it is always + available. + index 1 to 25 - 8 variable trasmit interrupts, variable 16 receive interrupts + and 1 optional lpi interrupt. +- phy-mode: String, operation mode of the PHY interface. + Supported values are: "sgmii", "xgmii". +- samsung,pbl: Integer, Programmable Burst Length. + Supported values are 1, 2, 4, 8, 16, or 32. +- samsung,burst-map: Integer, Program the possible bursts supported by sxgbe + This is an interger and represents allowable DMA bursts when fixed burst. + Allowable range is 0x01-0x3F. When this field is set fixed burst is enabled. + When fixed length is needed for burst mode, it can be set within allowable + range. + +Optional properties: +- mac-address: 6 bytes, mac address +- max-frame-size: Maximum Transfer Unit (IEEE defined MTU), rather + than the maximum frame size. + +Example: + + aliases { + ethernet0 = <&sxgbe0>; + }; + + sxgbe0: ethernet@1a040000 { + compatible = "samsung,sxgbe-v2.0a"; + reg = <0 0x1a040000 0 0x10000>; + interrupt-parent = <&gic>; + interrupts = <0 209 4>, <0 185 4>, <0 186 4>, <0 187 4>, + <0 188 4>, <0 189 4>, <0 190 4>, <0 191 4>, + <0 192 4>, <0 193 4>, <0 194 4>, <0 195 4>, + <0 196 4>, <0 197 4>, <0 198 4>, <0 199 4>, + <0 200 4>, <0 201 4>, <0 202 4>, <0 203 4>, + <0 204 4>, <0 205 4>, <0 206 4>, <0 207 4>, + <0 208 4>, <0 210 4>; + samsung,pbl = <0x08> + samsung,burst-map = <0x20> + mac-address = [ 00 11 22 33 44 55 ]; /* Filled in by U-Boot */ + max-frame-size = <9000>; + phy-mode = "xgmii"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 349a993fbda6..f779c91122bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7550,6 +7550,15 @@ S: Supported L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) F: drivers/clk/samsung/ +SAMSUNG SXGBE DRIVERS +M: Byungho An <bh74.an@samsung.com> +M: Girish K S <ks.giri@samsung.com> +M: Siva Reddy Kallam <siva.kallam@samsung.com> +M: Vipul Pandya <vipul.pandya@samsung.com> +S: Supported +L: netdev@vger.kernel.org +F: drivers/net/ethernet/samsung/sxgbe/ + SERIAL DRIVERS M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> L: linux-serial@vger.kernel.org diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 39484b534f5e..39b26fe28d10 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -150,6 +150,7 @@ config S6GMAC To compile this driver as a module, choose M here. The module will be called s6gmac. +source "drivers/net/ethernet/samsung/Kconfig" source "drivers/net/ethernet/seeq/Kconfig" source "drivers/net/ethernet/silan/Kconfig" source "drivers/net/ethernet/sis/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index adf61af507f7..545d0b3b9cb4 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ obj-$(CONFIG_SH_ETH) += renesas/ obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ obj-$(CONFIG_S6GMAC) += s6gmac.o +obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/ obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/ obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ obj-$(CONFIG_NET_VENDOR_SIS) += sis/ diff --git a/drivers/net/ethernet/samsung/Kconfig b/drivers/net/ethernet/samsung/Kconfig new file mode 100644 index 000000000000..7902341f2623 --- /dev/null +++ b/drivers/net/ethernet/samsung/Kconfig @@ -0,0 +1,16 @@ +# +# Samsung Ethernet device configuration +# + +config NET_VENDOR_SAMSUNG + bool "Samsung Ethernet device" + default y + ---help--- + This is the driver for the SXGBE 10G Ethernet IP block found on Samsung + platforms. + +if NET_VENDOR_SAMSUNG + +source "drivers/net/ethernet/samsung/sxgbe/Kconfig" + +endif # NET_VENDOR_SAMSUNG diff --git a/drivers/net/ethernet/samsung/Makefile b/drivers/net/ethernet/samsung/Makefile new file mode 100644 index 000000000000..1773c29b8d76 --- /dev/null +++ b/drivers/net/ethernet/samsung/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Samsung Ethernet device drivers. +# + +obj-$(CONFIG_SXGBE_ETH) += sxgbe/ diff --git a/drivers/net/ethernet/samsung/sxgbe/Kconfig b/drivers/net/ethernet/samsung/sxgbe/Kconfig new file mode 100644 index 000000000000..d79288c51d0a --- /dev/null +++ b/drivers/net/ethernet/samsung/sxgbe/Kconfig @@ -0,0 +1,9 @@ +config SXGBE_ETH + tristate "Samsung 10G/2.5G/1G SXGBE Ethernet driver" + depends on HAS_IOMEM && HAS_DMA + select PHYLIB + select CRC32 + select PTP_1588_CLOCK + ---help--- + This is the driver for the SXGBE 10G Ethernet IP block found on Samsung + platforms. diff --git a/drivers/net/ethernet/samsung/sxgbe/Makefile b/drivers/net/ethernet/samsung/sxgbe/Makefile new file mode 100644 index 000000000000..dcc80b9d4370 --- /dev/null +++ b/drivers/net/ethernet/samsung/sxgbe/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_SXGBE_ETH) += samsung-sxgbe.o +samsung-sxgbe-objs:= sxgbe_platform.o sxgbe_main.o sxgbe_desc.o \ + sxgbe_dma.o sxgbe_core.o sxgbe_mtl.o sxgbe_mdio.o \ + sxgbe_ethtool.o sxgbe_xpcs.o $(samsung-sxgbe-y) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h new file mode 100644 index 000000000000..6203c7d8550f --- /dev/null +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h @@ -0,0 +1,535 @@ +/* 10G controller driver for Samsung SoCs + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Siva Reddy Kallam <siva.kallam@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SXGBE_COMMON_H__ +#define __SXGBE_COMMON_H__ + +/* forward references */ +struct sxgbe_desc_ops; +struct sxgbe_dma_ops; +struct sxgbe_mtl_ops; + +#define SXGBE_RESOURCE_NAME "sam_sxgbeeth" +#define DRV_MODULE_VERSION "November_2013" + +/* MAX HW feature words */ +#define SXGBE_HW_WORDS 3 + +#define SXGBE_RX_COE_NONE 0 + +/* CSR Frequency Access Defines*/ +#define SXGBE_CSR_F_150M 150000000 +#define SXGBE_CSR_F_250M 250000000 +#define SXGBE_CSR_F_300M 300000000 +#define SXGBE_CSR_F_350M 350000000 +#define SXGBE_CSR_F_400M 400000000 +#define SXGBE_CSR_F_500M 500000000 + +/* pause time */ +#define SXGBE_PAUSE_TIME 0x200 + +/* tx queues */ +#define SXGBE_TX_QUEUES 8 +#define SXGBE_RX_QUEUES 16 + +/* Calculated based how much time does it take to fill 256KB Rx memory + * at 10Gb speed at 156MHz clock rate and considered little less then + * the actual value. + */ +#define SXGBE_MAX_DMA_RIWT 0x70 +#define SXGBE_MIN_DMA_RIWT 0x01 + +/* Tx coalesce parameters */ +#define SXGBE_COAL_TX_TIMER 40000 +#define SXGBE_MAX_COAL_TX_TICK 100000 +#define SXGBE_TX_MAX_FRAMES 512 +#define SXGBE_TX_FRAMES 128 + +/* SXGBE TX FIFO is 8K, Rx FIFO is 16K */ +#define BUF_SIZE_16KiB 16384 +#define BUF_SIZE_8KiB 8192 +#define BUF_SIZE_4KiB 4096 +#define BUF_SIZE_2KiB 2048 + +#define SXGBE_DEFAULT_LIT_LS 0x3E8 +#define SXGBE_DEFAULT_TWT_LS 0x0 + +/* Flow Control defines */ +#define SXGBE_FLOW_OFF 0 +#define SXGBE_FLOW_RX 1 +#define SXGBE_FLOW_TX 2 +#define SXGBE_FLOW_AUTO (SXGBE_FLOW_TX | SXGBE_FLOW_RX) + +#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ + +/* errors */ +#define RX_GMII_ERR 0x01 +#define RX_WATCHDOG_ERR 0x02 +#define RX_CRC_ERR 0x03 +#define RX_GAINT_ERR 0x04 +#define RX_IP_HDR_ERR 0x05 +#define RX_PAYLOAD_ERR 0x06 +#define RX_OVERFLOW_ERR 0x07 + +/* pkt type */ +#define RX_LEN_PKT 0x00 +#define RX_MACCTL_PKT 0x01 +#define RX_DCBCTL_PKT 0x02 +#define RX_ARP_PKT 0x03 +#define RX_OAM_PKT 0x04 +#define RX_UNTAG_PKT 0x05 +#define RX_OTHER_PKT 0x07 +#define RX_SVLAN_PKT 0x08 +#define RX_CVLAN_PKT 0x09 +#define RX_DVLAN_OCVLAN_ICVLAN_PKT 0x0A +#define RX_DVLAN_OSVLAN_ISVLAN_PKT 0x0B +#define RX_DVLAN_OSVLAN_ICVLAN_PKT 0x0C +#define RX_DVLAN_OCVLAN_ISVLAN_PKT 0x0D + +#define RX_NOT_IP_PKT 0x00 +#define RX_IPV4_TCP_PKT 0x01 +#define RX_IPV4_UDP_PKT 0x02 +#define RX_IPV4_ICMP_PKT 0x03 +#define RX_IPV4_UNKNOWN_PKT 0x07 +#define RX_IPV6_TCP_PKT 0x09 +#define RX_IPV6_UDP_PKT 0x0A +#define RX_IPV6_ICMP_PKT 0x0B +#define RX_IPV6_UNKNOWN_PKT 0x0F + +#define RX_NO_PTP 0x00 +#define RX_PTP_SYNC 0x01 +#define RX_PTP_FOLLOW_UP 0x02 +#define RX_PTP_DELAY_REQ 0x03 +#define RX_PTP_DELAY_RESP 0x04 +#define RX_PTP_PDELAY_REQ 0x05 +#define RX_PTP_PDELAY_RESP 0x06 +#define RX_PTP_PDELAY_FOLLOW_UP 0x07 +#define RX_PTP_ANNOUNCE 0x08 +#define RX_PTP_MGMT 0x09 +#define RX_PTP_SIGNAL 0x0A +#define RX_PTP_RESV_MSG 0x0F + +/* EEE-LPI mode flags*/ +#define TX_ENTRY_LPI_MODE 0x10 +#define TX_EXIT_LPI_MODE 0x20 +#define RX_ENTRY_LPI_MODE 0x40 +#define RX_EXIT_LPI_MODE 0x80 + +/* EEE-LPI Interrupt status flag */ +#define LPI_INT_STATUS BIT(5) + +/* EEE-LPI Default timer values */ +#define LPI_LINK_STATUS_TIMER 0x3E8 +#define LPI_MAC_WAIT_TIMER 0x00 + +/* EEE-LPI Control and status definitions */ +#define LPI_CTRL_STATUS_TXA BIT(19) +#define LPI_CTRL_STATUS_PLSDIS BIT(18) +#define LPI_CTRL_STATUS_PLS BIT(17) +#define LPI_CTRL_STATUS_LPIEN BIT(16) +#define LPI_CTRL_STATUS_TXRSTP BIT(11) +#define LPI_CTRL_STATUS_RXRSTP BIT(10) +#define LPI_CTRL_STATUS_RLPIST BIT(9) +#define LPI_CTRL_STATUS_TLPIST BIT(8) +#define LPI_CTRL_STATUS_RLPIEX BIT(3) +#define LPI_CTRL_STATUS_RLPIEN BIT(2) +#define LPI_CTRL_STATUS_TLPIEX BIT(1) +#define LPI_CTRL_STATUS_TLPIEN BIT(0) + +enum dma_irq_status { + tx_hard_error = BIT(0), + tx_bump_tc = BIT(1), + handle_tx = BIT(2), + rx_hard_error = BIT(3), + rx_bump_tc = BIT(4), + handle_rx = BIT(5), +}; + +#define NETIF_F_HW_VLAN_ALL (NETIF_F_HW_VLAN_CTAG_RX | \ + NETIF_F_HW_VLAN_STAG_RX | \ + NETIF_F_HW_VLAN_CTAG_TX | \ + NETIF_F_HW_VLAN_STAG_TX | \ + NETIF_F_HW_VLAN_CTAG_FILTER | \ + NETIF_F_HW_VLAN_STAG_FILTER) + +/* MMC control defines */ +#define SXGBE_MMC_CTRL_CNT_FRZ 0x00000008 + +/* SXGBE HW ADDR regs */ +#define SXGBE_ADDR_HIGH(reg) (((reg > 15) ? 0x00000800 : 0x00000040) + \ + (reg * 8)) +#define SXGBE_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \ + (reg * 8)) +#define SXGBE_MAX_PERFECT_ADDRESSES 32 /* Maximum unicast perfect filtering */ +#define SXGBE_FRAME_FILTER 0x00000004 /* Frame Filter */ + +/* SXGBE Frame Filter defines */ +#define SXGBE_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */ +#define SXGBE_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */ +#define SXGBE_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */ +#define SXGBE_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */ +#define SXGBE_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */ +#define SXGBE_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */ +#define SXGBE_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */ +#define SXGBE_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */ +#define SXGBE_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */ +#define SXGBE_FRAME_FILTER_RA 0x80000000 /* Receive all mode */ + +#define SXGBE_HASH_TABLE_SIZE 64 +#define SXGBE_HASH_HIGH 0x00000008 /* Multicast Hash Table High */ +#define SXGBE_HASH_LOW 0x0000000c /* Multicast Hash Table Low */ + +#define SXGBE_HI_REG_AE 0x80000000 + +/* Minimum and maximum MTU */ +#define MIN_MTU 68 +#define MAX_MTU 9000 + +#define SXGBE_FOR_EACH_QUEUE(max_queues, queue_num) \ + for (queue_num = 0; queue_num < max_queues; queue_num++) + +#define DRV_VERSION "1.0.0" + +#define SXGBE_MAX_RX_CHANNELS 16 +#define SXGBE_MAX_TX_CHANNELS 16 + +#define START_MAC_REG_OFFSET 0x0000 +#define MAX_MAC_REG_OFFSET 0x0DFC +#define START_MTL_REG_OFFSET 0x1000 +#define MAX_MTL_REG_OFFSET 0x18FC +#define START_DMA_REG_OFFSET 0x3000 +#define MAX_DMA_REG_OFFSET 0x38FC + +#define REG_SPACE_SIZE 0x2000 + +/* sxgbe statistics counters */ +struct sxgbe_extra_stats { + /* TX/RX IRQ events */ + unsigned long tx_underflow_irq; + unsigned long tx_process_stopped_irq; + unsigned long tx_ctxt_desc_err; + unsigned long tx_threshold; + unsigned long rx_threshold; + unsigned long tx_pkt_n; + unsigned long rx_pkt_n; + unsigned long normal_irq_n; + unsigned long tx_normal_irq_n; + unsigned long rx_normal_irq_n; + unsigned long napi_poll; + unsigned long tx_clean; + unsigned long tx_reset_ic_bit; + unsigned long rx_process_stopped_irq; + unsigned long rx_underflow_irq; + + /* Bus access errors */ + unsigned long fatal_bus_error_irq; + unsigned long tx_read_transfer_err; + unsigned long tx_write_transfer_err; + unsigned long tx_desc_access_err; + unsigned long tx_buffer_access_err; + unsigned long tx_data_transfer_err; + unsigned long rx_read_transfer_err; + unsigned long rx_write_transfer_err; + unsigned long rx_desc_access_err; + unsigned long rx_buffer_access_err; + unsigned long rx_data_transfer_err; + + /* EEE-LPI stats */ + unsigned long tx_lpi_entry_n; + unsigned long tx_lpi_exit_n; + unsigned long rx_lpi_entry_n; + unsigned long rx_lpi_exit_n; + unsigned long eee_wakeup_error_n; + + /* RX specific */ + /* L2 error */ + unsigned long rx_code_gmii_err; + unsigned long rx_watchdog_err; + unsigned long rx_crc_err; + unsigned long rx_gaint_pkt_err; + unsigned long ip_hdr_err; + unsigned long ip_payload_err; + unsigned long overflow_error; + + /* L2 Pkt type */ + unsigned long len_pkt; + unsigned long mac_ctl_pkt; + unsigned long dcb_ctl_pkt; + unsigned long arp_pkt; + unsigned long oam_pkt; + unsigned long untag_okt; + unsigned long other_pkt; + unsigned long svlan_tag_pkt; + unsigned long cvlan_tag_pkt; + unsigned long dvlan_ocvlan_icvlan_pkt; + unsigned long dvlan_osvlan_isvlan_pkt; + unsigned long dvlan_osvlan_icvlan_pkt; + unsigned long dvan_ocvlan_icvlan_pkt; + + /* L3/L4 Pkt type */ + unsigned long not_ip_pkt; + unsigned long ip4_tcp_pkt; + unsigned long ip4_udp_pkt; + unsigned long ip4_icmp_pkt; + unsigned long ip4_unknown_pkt; + unsigned long ip6_tcp_pkt; + unsigned long ip6_udp_pkt; + unsigned long ip6_icmp_pkt; + unsigned long ip6_unknown_pkt; + + /* Filter specific */ + unsigned long vlan_filter_match; + unsigned long sa_filter_fail; + unsigned long da_filter_fail; + unsigned long hash_filter_pass; + unsigned long l3_filter_match; + unsigned long l4_filter_match; + + /* RX context specific */ + unsigned long timestamp_dropped; + unsigned long rx_msg_type_no_ptp; + unsigned long rx_ptp_type_sync; + unsigned long rx_ptp_type_follow_up; + unsigned long rx_ptp_type_delay_req; + unsigned long rx_ptp_type_delay_resp; + unsigned long rx_ptp_type_pdelay_req; + unsigned long rx_ptp_type_pdelay_resp; + unsigned long rx_ptp_type_pdelay_follow_up; + unsigned long rx_ptp_announce; + unsigned long rx_ptp_mgmt; + unsigned long rx_ptp_signal; + unsigned long rx_ptp_resv_msg_type; +}; + +struct mac_link { + int port; + int duplex; + int speed; +}; + +struct mii_regs { + unsigned int addr; /* MII Address */ + unsigned int data; /* MII Data */ +}; + +struct sxgbe_core_ops { + /* MAC core initialization */ + void (*core_init)(void __iomem *ioaddr); + /* Dump MAC registers */ + void (*dump_regs)(void __iomem *ioaddr); + /* Handle extra events on specific interrupts hw dependent */ + int (*host_irq_status)(void __iomem *ioaddr, + struct sxgbe_extra_stats *x); + /* Set power management mode (e.g. magic frame) */ + void (*pmt)(void __iomem *ioaddr, unsigned long mode); + /* Set/Get Unicast MAC addresses */ + void (*set_umac_addr)(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); + void (*get_umac_addr)(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); + void (*enable_rx)(void __iomem *ioaddr, bool enable); + void (*enable_tx)(void __iomem *ioaddr, bool enable); + + /* controller version specific operations */ + int (*get_controller_version)(void __iomem *ioaddr); + + /* If supported then get the optional core features */ + unsigned int (*get_hw_feature)(void __iomem *ioaddr, + unsigned char feature_index); + /* adjust SXGBE speed */ + void (*set_speed)(void __iomem *ioaddr, unsigned char speed); + + /* EEE-LPI specific operations */ + void (*set_eee_mode)(void __iomem *ioaddr); + void (*reset_eee_mode)(void __iomem *ioaddr); + void (*set_eee_timer)(void __iomem *ioaddr, const int ls, + const int tw); + void (*set_eee_pls)(void __iomem *ioaddr, const int link); + + /* Enable disable checksum offload operations */ + void (*enable_rx_csum)(void __iomem *ioaddr); + void (*disable_rx_csum)(void __iomem *ioaddr); +}; + +const struct sxgbe_core_ops *sxgbe_get_core_ops(void); + +struct sxgbe_ops { + const struct sxgbe_core_ops *mac; + const struct sxgbe_desc_ops *desc; + const struct sxgbe_dma_ops *dma; + const struct sxgbe_mtl_ops *mtl; + struct mii_regs mii; /* MII register Addresses */ + struct mac_link link; + unsigned int ctrl_uid; + unsigned int ctrl_id; +}; + +/* SXGBE private data structures */ +struct sxgbe_tx_queue { + unsigned int irq_no; + struct sxgbe_priv_data *priv_ptr; + struct sxgbe_tx_norm_desc *dma_tx; + dma_addr_t dma_tx_phy; + dma_addr_t *tx_skbuff_dma; + struct sk_buff **tx_skbuff; + struct timer_list txtimer; + spinlock_t tx_lock; /* lock for tx queues */ + unsigned int cur_tx; + unsigned int dirty_tx; + u32 tx_count_frames; + u32 tx_coal_frames; + u32 tx_coal_timer; + int hwts_tx_en; + u16 prev_mss; + u8 queue_no; +}; + +struct sxgbe_rx_queue { + struct sxgbe_priv_data *priv_ptr; + struct sxgbe_rx_norm_desc *dma_rx; + struct sk_buff **rx_skbuff; + unsigned int cur_rx; + unsigned int dirty_rx; + unsigned int irq_no; + u32 rx_riwt; + dma_addr_t *rx_skbuff_dma; + dma_addr_t dma_rx_phy; + u8 queue_no; +}; + +/* SXGBE HW capabilities */ +struct sxgbe_hw_features { + /****** CAP [0] *******/ + unsigned int pmt_remote_wake_up; + unsigned int pmt_magic_frame; + /* IEEE 1588-2008 */ + unsigned int atime_stamp; + + unsigned int eee; + + unsigned int tx_csum_offload; + unsigned int rx_csum_offload; + unsigned int multi_macaddr; + unsigned int tstamp_srcselect; + unsigned int sa_vlan_insert; + + /****** CAP [1] *******/ + unsigned int rxfifo_size; + unsigned int txfifo_size; + unsigned int atstmap_hword; + unsigned int dcb_enable; + unsigned int splithead_enable; + unsigned int tcpseg_offload; + unsigned int debug_mem; + unsigned int rss_enable; + unsigned int hash_tsize; + unsigned int l3l4_filer_size; + + /* This value is in bytes and + * as mentioned in HW features + * of SXGBE data book + */ + unsigned int rx_mtl_qsize; + unsigned int tx_mtl_qsize; + + /****** CAP [2] *******/ + /* TX and RX number of channels */ + unsigned int rx_mtl_queues; + unsigned int tx_mtl_queues; + unsigned int rx_dma_channels; + unsigned int tx_dma_channels; + unsigned int pps_output_count; + unsigned int aux_input_count; +}; + +struct sxgbe_priv_data { + /* DMA descriptos */ + struct sxgbe_tx_queue *txq[SXGBE_TX_QUEUES]; + struct sxgbe_rx_queue *rxq[SXGBE_RX_QUEUES]; + u8 cur_rx_qnum; + + unsigned int dma_tx_size; + unsigned int dma_rx_size; + unsigned int dma_buf_sz; + u32 rx_riwt; + + struct napi_struct napi; + + void __iomem *ioaddr; + struct net_device *dev; + struct device *device; + struct sxgbe_ops *hw; /* sxgbe specific ops */ + int no_csum_insertion; + int irq; + int rxcsum_insertion; + spinlock_t stats_lock; /* lock for tx/rx statatics */ + + struct phy_device *phydev; + int oldlink; + int speed; + int oldduplex; + struct mii_bus *mii; + int mii_irq[PHY_MAX_ADDR]; + u8 rx_pause; + u8 tx_pause; + + struct sxgbe_extra_stats xstats; + struct sxgbe_plat_data *plat; + struct sxgbe_hw_features hw_cap; + + u32 msg_enable; + + struct clk *sxgbe_clk; + int clk_csr; + unsigned int mode; + unsigned int default_addend; + + /* advanced time stamp support */ + u32 adv_ts; + int use_riwt; + struct ptp_clock *ptp_clock; + + /* tc control */ + int tx_tc; + int rx_tc; + /* EEE-LPI specific members */ + struct timer_list eee_ctrl_timer; + bool tx_path_in_lpi_mode; + int lpi_irq; + int eee_enabled; + int eee_active; + int tx_lpi_timer; +}; + +/* Function prototypes */ +struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device, + struct sxgbe_plat_data *plat_dat, + void __iomem *addr); +int sxgbe_drv_remove(struct net_device *ndev); +void sxgbe_set_ethtool_ops(struct net_device *netdev); +int sxgbe_mdio_unregister(struct net_device *ndev); +int sxgbe_mdio_register(struct net_device *ndev); +int sxgbe_register_platform(void); +void sxgbe_unregister_platform(void); + +#ifdef CONFIG_PM +int sxgbe_suspend(struct net_device *ndev); +int sxgbe_resume(struct net_device *ndev); +int sxgbe_freeze(struct net_device *ndev); +int sxgbe_restore(struct net_device *ndev); +#endif /* CONFIG_PM */ + +const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void); + +void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv); +bool sxgbe_eee_init(struct sxgbe_priv_data * const priv); +#endif /* __SXGBE_COMMON_H__ */ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c new file mode 100644 index 000000000000..66d4a74a137c --- /dev/null +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c @@ -0,0 +1,262 @@ +/* 10G controller driver for Samsung SoCs + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Siva Reddy Kallam <siva.kallam@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/export.h> +#include <linux/io.h> +#include <linux/netdevice.h> +#include <linux/phy.h> + +#include "sxgbe_common.h" +#include "sxgbe_reg.h" + +/* MAC core initialization */ +static void sxgbe_core_init(void __iomem *ioaddr) +{ + u32 regval; + + /* TX configuration */ + regval = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG); + /* Other configurable parameters IFP, IPG, ISR, ISM + * needs to be set if needed + */ + regval |= SXGBE_TX_JABBER_DISABLE; + writel(regval, ioaddr + SXGBE_CORE_TX_CONFIG_REG); + + /* RX configuration */ + regval = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG); + /* Other configurable parameters CST, SPEN, USP, GPSLCE + * WD, LM, S2KP, HDSMS, GPSL, ELEN, ARPEN needs to be + * set if needed + */ + regval |= SXGBE_RX_JUMBPKT_ENABLE | SXGBE_RX_ACS_ENABLE; + writel(regval, ioaddr + SXGBE_CORE_RX_CONFIG_REG); +} + +/* Dump MAC registers */ +static void sxgbe_core_dump_regs(void __iomem *ioaddr) +{ +} + +static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status) +{ + int status = 0; + int lpi_status; + + /* Reading this register shall clear all the LPI status bits */ + lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); + + if (lpi_status & LPI_CTRL_STATUS_TLPIEN) + status |= TX_ENTRY_LPI_MODE; + if (lpi_status & LPI_CTRL_STATUS_TLPIEX) + status |= TX_EXIT_LPI_MODE; + if (lpi_status & LPI_CTRL_STATUS_RLPIEN) + status |= RX_ENTRY_LPI_MODE; + if (lpi_status & LPI_CTRL_STATUS_RLPIEX) + status |= RX_EXIT_LPI_MODE; + + return status; +} + +/* Handle extra events on specific interrupts hw dependent */ +static int sxgbe_core_host_irq_status(void __iomem *ioaddr, + struct sxgbe_extra_stats *x) +{ + int irq_status, status = 0; + + irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG); + + if (unlikely(irq_status & LPI_INT_STATUS)) + status |= sxgbe_get_lpi_status(ioaddr, irq_status); + + return status; +} + +/* Set power management mode (e.g. magic frame) */ +static void sxgbe_core_pmt(void __iomem *ioaddr, unsigned long mode) +{ +} + +/* Set/Get Unicast MAC addresses */ +static void sxgbe_core_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + u32 high_word, low_word; + + high_word = (addr[5] << 8) || (addr[4]); + low_word = ((addr[3] << 24) || (addr[2] << 16) || + (addr[1] << 8) || (addr[0])); + writel(high_word, ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n)); + writel(low_word, ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n)); +} + +static void sxgbe_core_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + u32 high_word, low_word; + + high_word = readl(ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n)); + low_word = readl(ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n)); + + /* extract and assign address */ + addr[5] = (high_word & 0x0000FF00) >> 8; + addr[4] = (high_word & 0x000000FF); + addr[3] = (low_word & 0xFF000000) >> 24; + addr[2] = (low_word & 0x00FF0000) >> 16; + addr[1] = (low_word & 0x0000FF00) >> 8; + addr[0] = (low_word & 0x000000FF); +} + +static void sxgbe_enable_tx(void __iomem *ioaddr, bool enable) +{ + u32 tx_config; + + tx_config = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG); + tx_config &= ~SXGBE_TX_ENABLE; + + if (enable) + tx_config |= SXGBE_TX_ENABLE; + writel(tx_config, ioaddr + SXGBE_CORE_TX_CONFIG_REG); +} + +static void sxgbe_enable_rx(void __iomem *ioaddr, bool enable) +{ + u32 rx_config; + + rx_config = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG); + rx_config &= ~SXGBE_RX_ENABLE; + + if (enable) + rx_config |= SXGBE_RX_ENABLE; + writel(rx_config, ioaddr + SXGBE_CORE_RX_CONFIG_REG); +} + +static int sxgbe_get_controller_version(void __iomem *ioaddr) +{ + return readl(ioaddr + SXGBE_CORE_VERSION_REG); +} + +/* If supported then get the optional core features */ +static unsigned int sxgbe_get_hw_feature(void __iomem *ioaddr, + unsigned char feature_index) +{ + return readl(ioaddr + (SXGBE_CORE_HW_FEA_REG(feature_index))); +} + +static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed) +{ + u32 tx_cfg = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG); + + /* clear the speed bits */ + tx_cfg &= ~0x60000000; + tx_cfg |= (speed << SXGBE_SPEED_LSHIFT); + + /* set the speed */ + writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG); +} + +static void sxgbe_set_eee_mode(void __iomem *ioaddr) +{ + u32 ctrl; + + /* Enable the LPI mode for transmit path with Tx automate bit set. + * When Tx Automate bit is set, MAC internally handles the entry + * to LPI mode after all outstanding and pending packets are + * transmitted. + */ + ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); + ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA; + writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); +} + +static void sxgbe_reset_eee_mode(void __iomem *ioaddr) +{ + u32 ctrl; + + ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); + ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA); + writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); +} + +static void sxgbe_set_eee_pls(void __iomem *ioaddr, const int link) +{ + u32 ctrl; + + ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); + + /* If the PHY link status is UP then set PLS */ + if (link) + ctrl |= LPI_CTRL_STATUS_PLS; + else + ctrl &= ~LPI_CTRL_STATUS_PLS; + + writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS); +} + +static void sxgbe_set_eee_timer(void __iomem *ioaddr, + const int ls, const int tw) +{ + int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16); + + /* Program the timers in the LPI timer control register: + * LS: minimum time (ms) for which the link + * status from PHY should be ok before transmitti |
