/*------------------------------------------------------------------------------------------*\ * Copyright (C) 2011,2012 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*------------------------------------------------------------------------------------------*/ #if !defined(__AVM_NET_ATHEROS_MAC_) #define __AVM_NET_ATHEROS_MAC_ #include #include #include #include //#include "avmnet_module.h" //#include "avmnet_config.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) #define soc_is_ar934x is_ar934x #define soc_is_qca9531 is_qca9531 #define soc_is_qca953x is_qca953x #define soc_is_qca955x is_qca955x #define soc_is_qca956x is_qca956x #endif #define GMAC_MAX_ETH_DEVS 6 /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #define ENET_NUM_AC 4 /* 4 AC categories */ /* QOS stream classes */ #define ENET_AC_BE 0 /* best effort */ #define ENET_AC_BK 1 /* background */ #define ENET_AC_VI 2 /* video */ #define ENET_AC_VO 3 /* voice */ #define ATHR_PHY_SPEED_10T 0 #define ATHR_PHY_SPEED_100T 1 #define ATHR_PHY_SPEED_1000T 2 #define ATHR_PHY_SPEED_UNKNOWN 3 /*------------------------------------------------------------------------------------------*\ * IP needs 16 bit alignment. But RX DMA needs 4 bit alignment. We sacrifice IP * Plus Reserve extra head room for wmac \*------------------------------------------------------------------------------------------*/ #define ETHERNET_FCS_SIZE 4 /*--- #define ATHR_GMAC_RX_RESERVE (64) ---*/ /*--- wird schon mit NET_SKB_PAD_ALLOC erledigt ---*/ /*--- #define ATHR_GMAC_RX_BUF_SIZE (ATHR_GMAC_RX_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETHERNET_FCS_SIZE) ---*/ #define ATHR_GMAC_RX_BUF_SIZE (ETH_HLEN + ETH_FRAME_LEN + ETHERNET_FCS_SIZE) #define ATHR_GMAC_TX_FIFO_LEN 2048 #define ATHR_GMAC_TX_MIN_DS_LEN 128 #define ATHR_GMAC_TX_MAX_DS_LEN ATHR_GMAC_TX_FIFO_LEN #define ATHR_GMAC_TX_MTU_LEN 1536 #define ATHR_GMAC_NAPI_WEIGHT 64 #define ATHR_FIFO_BYTE_NIBBLE (1<<19) #define ATHR_FIFO_DROP_SHORT (1<<18) #define ATHR_FIFO_UNI (1<<17) #define ATHR_FIFO_TRUNC (1<<16) #define ATHR_FIFO_LONG (1<<15) #define ATHR_FIFO_VLAN (1<<14) #define ATHR_FIFO_UNSUP (1<<13) #define ATHR_FIFO_PAUSE (1<<12) #define ATHR_FIFO_CONTROL (1<<11) #define ATHR_FIFO_DRIBLLE (1<<10) #define ATHR_FIFO_BROADCAST (1<<9) #define ATHR_FIFO_MULTICAST (1<<8) #define ATHR_FIFO_OK (1<<7) #define ATHR_FIFO_OUT_RANGE (1<<6) #define ATHR_FIFO_LEN_MISMATCH (1<<5) #define ATHR_FIFO_CRC_ERROR (1<<4) #define ATHR_FIFO_CODE_ERROR (1<<3) #define ATHR_FIFO_FALSE_CARRIER (1<<2) #define ATHR_FIFO_RX_DV (1<<1) #define ATHR_FIFO_DROP (1<<0) #define ATHR_ALL_FRAMES 0x3FFFF #define ATHR_DEFAULT_FRAMES \ ( \ ATHR_FIFO_RX_DV | ATHR_FIFO_LEN_MISMATCH | ATHR_FIFO_OUT_RANGE | \ ATHR_FIFO_OK | ATHR_FIFO_MULTICAST | ATHR_FIFO_BROADCAST | \ ATHR_FIFO_CONTROL | ATHR_FIFO_UNSUP | ATHR_FIFO_VLAN | ATHR_FIFO_UNI | \ ATHR_FIFO_DROP_SHORT \ ) #define athr_mac_dma_cache_sync(b, c) \ do { \ dma_cache_sync(NULL, (void *)b, c, DMA_TO_DEVICE); \ } while (0) #define athr_mac_cache_inv(d, s) \ do { \ dma_cache_sync(NULL, (void *)d, s, DMA_FROM_DEVICE); \ } while (0) #define athr_gmac_reset_mask(_no) (_no) ? (ATH_RESET_GE1_MAC) : (ATH_RESET_GE0_MAC) /*------------------------------------------------------------------------------------------*\ * tx/rx stop start \*------------------------------------------------------------------------------------------*/ #define athr_gmac_tx_stopped(_mac_base) \ (!(athr_gmac_reg_rd((_mac_base), ATHR_GMAC_DMA_TX_CTRL) & ATHR_GMAC_TXE)) #define athr_gmac_rx_start(_mac_base) \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_RX_CTRL, ATHR_GMAC_RXE) #define athr_gmac_rx_stop(_mac_base) \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_RX_CTRL, 0) #define athr_gmac_tx_start_qos(_mac_base,ac) \ switch(ac) { \ case ENET_AC_VO: \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_CTRL_Q0, ATHR_GMAC_TXE); \ break; \ case ENET_AC_VI: \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_CTRL_Q1, ATHR_GMAC_TXE); \ break; \ case ENET_AC_BK: \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_CTRL_Q2, ATHR_GMAC_TXE); \ break; \ case ENET_AC_BE: \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_CTRL_Q3, ATHR_GMAC_TXE); \ break; \ } #define athr_gmac_tx_start(_mac_base) \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_CTRL_Q0, ATHR_GMAC_TXE) #define athr_gmac_tx_stop(_mac_base) \ athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_CTRL, 0) #define athr_gmac_ring_incr(_idx) \ if(unlikely(++(_idx) == r->ring_nelem)) (_idx) = 0; /*------------------------------------------------------------------------------------------*\ * ownership of descriptors between DMA and cpu \*------------------------------------------------------------------------------------------*/ #define athr_gmac_rx_owned_by_dma(_ds) ((_ds)->packet.Bits.is_empty == 1) #define athr_gmac_rx_give_to_dma(_ds) ((_ds)->packet.Bits.is_empty = 1) #define athr_gmac_tx_owned_by_dma(_ds) ((_ds)->packet.Bits.is_empty == 0) #define athr_gmac_tx_give_to_dma(_ds) ((_ds)->packet.Bits.is_empty = 0) #define athr_gmac_tx_own(_ds) ((_ds)->packet.Bits.is_empty = 1) /*------------------------------------------------------------------------------------------*\ * Interrupts \*------------------------------------------------------------------------------------------*/ #define ATHR_GMAC_INTR_MASK ( ATHR_GMAC_INTR_RX \ | ATHR_GMAC_INTR_RX_BUS_ERROR \ | ATHR_GMAC_INTR_TX_BUS_ERROR \ | ATHR_GMAC_INTR_RX_OVF \ /*--- | ATHR_GMAC_INTR_TX_URN ---*/ \ /*--- | ATHR_GMAC_INTR_TX ---*/ \ ) #define athr_gmac_get_isr(_mac_base) (athr_gmac_reg_rd(_mac_base, ATHR_GMAC_DMA_INTR) & (0xFFFF)) #define athr_gmac_get_msr(_mac_base) athr_gmac_reg_rd(_mac_base, ATHR_GMAC_DMA_INTR_MASK) #define athr_gmac_int_enable(_mac_base) athr_gmac_reg_wr(_mac_base, ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_MASK) #define athr_gmac_int_disable(_mac_base) athr_gmac_reg_wr(_mac_base, ATHR_GMAC_DMA_INTR_MASK, 0) /* * ACKS: * - We just write our bit - its write 1 to clear. * - These are not rmw's so we dont need locking around these. * - Txurn and rxovf are not fastpath and need consistency, so we use the flush * version of reg write. * - ack_rx is done every packet, and is largely only for statistical purposes; * so we use the no flush version and later cause an explicite flush. */ #define athr_gmac_intr_ack_txurn(_mac_base) athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_STATUS, ATHR_GMAC_TX_STATUS_URN); #define athr_gmac_intr_ack_rx(_mac_base) athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_RX_STATUS, ATHR_GMAC_RX_STATUS_PKT_RCVD); #define athr_gmac_intr_ack_rxovf(_mac_base) athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_RX_STATUS, ATHR_GMAC_RX_STATUS_OVF); #define athr_gmac_intr_ack_tx(_mac_base) athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_STATUS, ATHR_GMAC_TX_STATUS_PKT_SENT); #define athr_gmac_intr_ack_txbe(_mac_base) athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_TX_STATUS, ATHR_GMAC_TX_STATUS_BUS_ERROR); #define athr_gmac_intr_ack_rxbe(_mac_base) athr_gmac_reg_wr((_mac_base), ATHR_GMAC_DMA_RX_STATUS, ATHR_GMAC_RX_STATUS_BUS_ERROR); /* * Enable Disable. These are Read-Modify-Writes. Sometimes called from ISR * sometimes not. So the caller explicitely handles locking. */ #define athr_gmac_intr_disable_txurn(_mac_base) \ athr_gmac_reg_rmw_clear((_mac_base), ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_TX_URN); #define athr_gmac_intr_enable_txurn(_mac_base) \ athr_gmac_reg_rmw_set((_mac_base), ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_TX_URN); #define athr_gmac_intr_enable_tx(_mac_base) \ athr_gmac_reg_rmw_set((_mac_base), ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_TX); #define athr_gmac_intr_disable_tx(_mac_base) \ athr_gmac_reg_rmw_clear((_mac_base), ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_TX); #define athr_gmac_intr_disable_recv(_mac_base) \ athr_gmac_reg_rmw_clear(_mac_base, ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_RX ); #define athr_gmac_intr_enable_rxovf(_mac_base) \ athr_gmac_reg_rmw_set((_mac_base), ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_RX_OVF); #define athr_gmac_intr_disable_rxovf(_mac_base) \ athr_gmac_reg_rmw_clear(_mac_base, ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_RX_OVF); #define athr_gmac_intr_enable_recv(_mac_base) \ athr_gmac_reg_rmw_set(_mac_base, ATHR_GMAC_DMA_INTR_MASK, ATHR_GMAC_INTR_RX); #if defined(CONFIG_CPU_BIG_ENDIAN) #define addr_to_words(addr, w1, w2) { \ w1 = (addr[5] << 24) | (addr[4] << 16) | (addr[3] << 8) | addr[2]; \ w2 = (addr[1] << 24) | (addr[0] << 16) | 0; \ } #else #define addr_to_words(addr, w1, w2) { \ w1 = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; \ w2 = (addr[4] << 24) | (addr[5] << 16) | 0; \ } #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_MACH_AR934x) || defined(CONFIG_MACH_QCA956x) || \ defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA956X) /*--- diesen Header gibt es nur beim internen Switch - ein Header bei RX und TX ---*/ typedef struct __attribute__ ((packed)) _athr_special_header { unsigned short version : 2; unsigned short priority : 2; unsigned short type : 4; unsigned short from_cpu : 1; unsigned short portnum : 7; } athr_special_header_t ; typedef athr_special_header_t *p_athr_special_header_t; typedef struct __attribute__ ((packed)) _athr_special_tx_header { unsigned short version : 2; unsigned short priority : 2; unsigned short type : 4; unsigned short from_cpu : 1; unsigned short portnum : 7; } athr_special_tx_header_t ; typedef athr_special_tx_header_t *p_athr_special_tx_header_t; #else /*--- externe Switches - jeweils ein Header bei RX und einer bei TX ---*/ /*--- RX aus sich des Switches ---*/ typedef struct __attribute__ ((packed)) _athr_special_header { #if defined(__BIG_ENDIAN_BITFIELD) unsigned short version : 2; unsigned short priority : 3; unsigned short type : 3; unsigned short from_cpu : 1; unsigned short portnum : 7; #elif defined(__LITTLE_ENDIAN_BITFIELD) unsigned short portnum : 7; unsigned short from_cpu : 1; unsigned short type : 3; unsigned short priority : 3; unsigned short version : 2; #endif } athr_special_header_t ; typedef athr_special_header_t *p_athr_special_header_t; #endif typedef union __attribute__ ((packed)) _athr_mac_packet_header { struct __attribute__ ((packed)) __athr_mac_packet_header { unsigned char dest_mac[ETH_ALEN]; unsigned char source_mac[ETH_ALEN]; athr_special_header_t header; unsigned short data; } s; unsigned char buff[2 * ETH_ALEN + sizeof(athr_special_header_t) + sizeof(unsigned short)]; } athr_mac_packet_header_t ; /*------------------------------------------------------------------------------------------*\ * h/w descriptor \*------------------------------------------------------------------------------------------*/ typedef union _athr_mac_packet_ { uint32_t Register; struct _packet_ { uint32_t is_empty : 1; uint32_t res1 : 6; uint32_t more : 1; uint32_t res2 : 3; uint32_t ftpp_override : 5; uint32_t res3 : 2; uint32_t pkt_size : 14; } Bits; } athr_mac_packet; #define ATHR_TX_EMPTY (1<<31) #endif