| 1 | #include <linux/stddef.h> |
|---|
| 2 | #include <linux/autoconf.h> |
|---|
| 3 | #include <linux/module.h> |
|---|
| 4 | #include <linux/types.h> |
|---|
| 5 | #include <asm/byteorder.h> |
|---|
| 6 | #include <linux/init.h> |
|---|
| 7 | #include <linux/errno.h> |
|---|
| 8 | #include <linux/kernel.h> |
|---|
| 9 | #include <linux/netdevice.h> |
|---|
| 10 | #include <linux/etherdevice.h> |
|---|
| 11 | #include <linux/skbuff.h> |
|---|
| 12 | #include <linux/delay.h> |
|---|
| 13 | #include <linux/timer.h> |
|---|
| 14 | #include <linux/interrupt.h> |
|---|
| 15 | #include <linux/dma-mapping.h> |
|---|
| 16 | #include <linux/bitops.h> |
|---|
| 17 | #include <asm/irq.h> |
|---|
| 18 | #include <asm/io.h> |
|---|
| 19 | #include <net/sch_generic.h> |
|---|
| 20 | #include <asm/unaligned.h> |
|---|
| 21 | |
|---|
| 22 | #include "ag7100.h" |
|---|
| 23 | #include "ag7100_phy.h" |
|---|
| 24 | #include "ag7100_trc.h" |
|---|
| 25 | #ifdef CONFIG_BUFFALO |
|---|
| 26 | #include "rtl8366_smi.h" |
|---|
| 27 | RTL8366_FUNCS rtl_funcs = |
|---|
| 28 | { |
|---|
| 29 | NULL, |
|---|
| 30 | NULL, |
|---|
| 31 | NULL, |
|---|
| 32 | NULL, |
|---|
| 33 | NULL |
|---|
| 34 | }; |
|---|
| 35 | #endif //CONFIG_BUFFALO // |
|---|
| 36 | |
|---|
| 37 | unsigned int rx_hang_detect_pkt_cnt_all[2], rx_hang_detect_pkt_cnt_valid[2],rx_hang_detected[2]; |
|---|
| 38 | int set_mac_from_link_flag = 0; |
|---|
| 39 | static ag7100_mac_t *ag7100_macs[2]; |
|---|
| 40 | static void ag7100_hw_setup(ag7100_mac_t *mac); |
|---|
| 41 | static void ag7100_hw_stop(ag7100_mac_t *mac); |
|---|
| 42 | static void ag7100_oom_timer(unsigned long data); |
|---|
| 43 | static int ag7100_check_link(ag7100_mac_t *mac); |
|---|
| 44 | static int check_for_dma_hang(ag7100_mac_t *mac); |
|---|
| 45 | static int ag7100_tx_alloc(ag7100_mac_t *mac); |
|---|
| 46 | static int ag7100_rx_alloc(ag7100_mac_t *mac); |
|---|
| 47 | static void ag7100_rx_free(ag7100_mac_t *mac); |
|---|
| 48 | static void ag7100_tx_free(ag7100_mac_t *mac); |
|---|
| 49 | static int ag7100_ring_alloc(ag7100_ring_t *r, int count); |
|---|
| 50 | static int ag7100_rx_replenish(ag7100_mac_t *mac); |
|---|
| 51 | static int ag7100_tx_reap(ag7100_mac_t *mac); |
|---|
| 52 | static void ag7100_ring_release(ag7100_mac_t *mac, ag7100_ring_t *r); |
|---|
| 53 | static void ag7100_ring_free(ag7100_ring_t *r); |
|---|
| 54 | static void ag7100_tx_timeout_task(struct work_struct *work); |
|---|
| 55 | static void ag7100_get_default_macaddr(ag7100_mac_t *mac, u8 *mac_addr); |
|---|
| 56 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 57 | static int ag7100_poll(struct napi_struct *napi, int budget); |
|---|
| 58 | #else |
|---|
| 59 | static int ag7100_poll(struct net_device *dev, int *budget); |
|---|
| 60 | #endif |
|---|
| 61 | static void ag7100_buffer_free(struct sk_buff *skb); |
|---|
| 62 | void ag7100_dma_reset(ag7100_mac_t *mac); |
|---|
| 63 | int board_version; |
|---|
| 64 | int ag7100_recv_packets(struct net_device *dev, ag7100_mac_t *mac, |
|---|
| 65 | int max_work, int *work_done); |
|---|
| 66 | static irqreturn_t ag7100_intr(int cpl, void *dev_id); |
|---|
| 67 | static struct sk_buff * ag7100_buffer_alloc(void); |
|---|
| 68 | |
|---|
| 69 | char *mii_str[2][4] = { |
|---|
| 70 | {"GMii", "Mii", "RGMii", "RMii"}, |
|---|
| 71 | {"RGMii", "RMii", "INVL1", "INVL2"} |
|---|
| 72 | }; |
|---|
| 73 | char *spd_str[] = {"10Mbps", "100Mbps", "1000Mbps"}; |
|---|
| 74 | char *dup_str[] = {"half duplex", "full duplex"}; |
|---|
| 75 | |
|---|
| 76 | #define MODULE_NAME "AG7100" |
|---|
| 77 | |
|---|
| 78 | /* if 0 compute in init */ |
|---|
| 79 | int tx_len_per_ds = 0; |
|---|
| 80 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 81 | void ag7100_tx_flush(ag7100_mac_t *mac); |
|---|
| 82 | void howl_10baset_war(ag7100_mac_t *mac); |
|---|
| 83 | #endif |
|---|
| 84 | module_param(tx_len_per_ds, int, 0); |
|---|
| 85 | MODULE_PARM_DESC(tx_len_per_ds, "Size of DMA chunk"); |
|---|
| 86 | |
|---|
| 87 | /* if 0 compute in init */ |
|---|
| 88 | int tx_max_desc_per_ds_pkt=0; |
|---|
| 89 | |
|---|
| 90 | /* if 0 compute in init */ |
|---|
| 91 | #ifdef CONFIG_AR9100 |
|---|
| 92 | int fifo_3 = 0x780008; |
|---|
| 93 | #else |
|---|
| 94 | int fifo_3 = 0; |
|---|
| 95 | #endif |
|---|
| 96 | module_param(fifo_3, int, 0); |
|---|
| 97 | MODULE_PARM_DESC(fifo_3, "fifo cfg 3 settings"); |
|---|
| 98 | |
|---|
| 99 | int mii0_if = AG7100_MII0_INTERFACE; |
|---|
| 100 | module_param(mii0_if, int, 0); |
|---|
| 101 | MODULE_PARM_DESC(mii0_if, "mii0 connect"); |
|---|
| 102 | |
|---|
| 103 | int mii1_if = AG7100_MII1_INTERFACE; |
|---|
| 104 | module_param(mii1_if, int, 0); |
|---|
| 105 | MODULE_PARM_DESC(mii1_if, "mii1 connect"); |
|---|
| 106 | #ifndef CONFIG_AR9100 |
|---|
| 107 | #ifdef CONFIG_CAMEO_REALTEK_PHY |
|---|
| 108 | int gige_pll = 0x11110000; |
|---|
| 109 | int rtl_chip_type_select(void); |
|---|
| 110 | #else |
|---|
| 111 | int gige_pll = 0x0110000; |
|---|
| 112 | #endif |
|---|
| 113 | unsigned int e1000sr_pll[2] = { 0x1e000100ul, 0x1e000100ul }; |
|---|
| 114 | unsigned int e1000rb_pll[2] = { 0x1f000000ul, 0x00000100ul }; |
|---|
| 115 | unsigned int e100sr_pll[2] = { 0x13000a44ul, 0x13000a44ul }; |
|---|
| 116 | unsigned int e100rb_pll[2] = { 0x13000a44ul, 0x13000a44ul }; |
|---|
| 117 | unsigned int e10sr_pll[2] = { 0x13000a44ul, 0x00441099ul }; |
|---|
| 118 | unsigned int e10rb_pll[2] = { 0x13000a44ul, 0x00441099ul }; |
|---|
| 119 | unsigned int * e1000_pll; |
|---|
| 120 | unsigned int * e100_pll; |
|---|
| 121 | unsigned int * e10_pll; |
|---|
| 122 | #else |
|---|
| 123 | #ifdef CONFIG_BUFFALO |
|---|
| 124 | unsigned int e1000sr_pll[2] = { 0x1e000100ul, 0x1e000100ul }; |
|---|
| 125 | #ifdef CONFIG_TPLINK |
|---|
| 126 | unsigned int e1000rb_pll[2] = { 0x1a000000ul, 0x1a000000ul }; |
|---|
| 127 | #else |
|---|
| 128 | unsigned int e1000rb_pll[2] = { 0x1f000000ul, 0x00000100ul }; |
|---|
| 129 | #endif |
|---|
| 130 | |
|---|
| 131 | unsigned int e100sr_pll[2] = { 0x13000a44ul, 0x13000a44ul }; |
|---|
| 132 | unsigned int e100rb_pll[2] = { 0x13000a44ul, 0x13000a44ul }; |
|---|
| 133 | unsigned int e10sr_pll[2] = { 0x13000a44ul, 0x00441099ul }; |
|---|
| 134 | unsigned int e10rb_pll[2] = { 0x13000a44ul, 0x00441099ul }; |
|---|
| 135 | unsigned int * e1000_pll; |
|---|
| 136 | unsigned int * e100_pll; |
|---|
| 137 | unsigned int * e10_pll; |
|---|
| 138 | #endif // CONFIG_BUFFALO // |
|---|
| 139 | #ifdef CONFIG_RTL8366RB_SMI |
|---|
| 140 | #define SW_PLL 0x1a000000ul |
|---|
| 141 | #elif defined(CONFIG_RTL8366RB_SMI_MODULE) |
|---|
| 142 | #define SW_PLL 0x1a000000ul |
|---|
| 143 | #else |
|---|
| 144 | #define SW_PLL 0x1f000000ul |
|---|
| 145 | #endif |
|---|
| 146 | |
|---|
| 147 | int gige_pll = 0x1a000000; |
|---|
| 148 | #endif |
|---|
| 149 | module_param(gige_pll, int, 0); |
|---|
| 150 | MODULE_PARM_DESC(gige_pll, "Pll for (R)GMII if"); |
|---|
| 151 | |
|---|
| 152 | /* |
|---|
| 153 | * Cfg 5 settings |
|---|
| 154 | * Weed out junk frames (CRC errored, short collision'ed frames etc.) |
|---|
| 155 | */ |
|---|
| 156 | int fifo_5 = 0x7ffef; |
|---|
| 157 | module_param(fifo_5, int, 0); |
|---|
| 158 | MODULE_PARM_DESC(fifo_5, "fifo cfg 5 settings"); |
|---|
| 159 | |
|---|
| 160 | #define addr_to_words(addr, w1, w2) { \ |
|---|
| 161 | w1 = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; \ |
|---|
| 162 | w2 = (addr[4] << 24) | (addr[5] << 16) | 0; \ |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | /* |
|---|
| 166 | * Defines specific to this implemention |
|---|
| 167 | */ |
|---|
| 168 | |
|---|
| 169 | #ifndef CONFIG_AG7100_LEN_PER_TX_DS |
|---|
| 170 | #error Please run menuconfig and define CONFIG_AG7100_LEN_PER_TX_DS |
|---|
| 171 | #endif |
|---|
| 172 | |
|---|
| 173 | #ifndef CONFIG_AG7100_NUMBER_TX_PKTS |
|---|
| 174 | #error Please run menuconfig and define CONFIG_AG7100_NUMBER_TX_PKTS |
|---|
| 175 | #endif |
|---|
| 176 | |
|---|
| 177 | #ifndef CONFIG_AG7100_NUMBER_RX_PKTS |
|---|
| 178 | #error Please run menuconfig and define CONFIG_AG7100_NUMBER_RX_PKTS |
|---|
| 179 | #endif |
|---|
| 180 | #define AG7100_TX_FIFO_LEN 2048 |
|---|
| 181 | #define AG7100_TX_MIN_DS_LEN 128 |
|---|
| 182 | #define AG7100_TX_MAX_DS_LEN AG7100_TX_FIFO_LEN |
|---|
| 183 | |
|---|
| 184 | #define AG7100_TX_MTU_LEN 1536 |
|---|
| 185 | |
|---|
| 186 | #define AG7100_TX_DESC_CNT CONFIG_AG7100_NUMBER_TX_PKTS*tx_max_desc_per_ds_pkt |
|---|
| 187 | #define AG7100_TX_REAP_THRESH AG7100_TX_DESC_CNT/2 |
|---|
| 188 | #define AG7100_TX_QSTART_THRESH 4*tx_max_desc_per_ds_pkt |
|---|
| 189 | |
|---|
| 190 | #define AG7100_RX_DESC_CNT CONFIG_AG7100_NUMBER_RX_PKTS |
|---|
| 191 | |
|---|
| 192 | #define AG7100_NAPI_WEIGHT 64 |
|---|
| 193 | #define AG7100_PHY_POLL_SECONDS 2 |
|---|
| 194 | int dma_flag = 0; |
|---|
| 195 | static inline int ag7100_tx_reap_thresh(ag7100_mac_t *mac) |
|---|
| 196 | { |
|---|
| 197 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 198 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 199 | if(mac->speed_10t) |
|---|
| 200 | return (ag7100_ndesc_unused(mac, r) < 2); |
|---|
| 201 | else |
|---|
| 202 | #endif |
|---|
| 203 | return (ag7100_ndesc_unused(mac, r) < AG7100_TX_REAP_THRESH); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | static inline int ag7100_tx_ring_full(ag7100_mac_t *mac) |
|---|
| 207 | { |
|---|
| 208 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 209 | |
|---|
| 210 | ag7100_trc_new(ag7100_ndesc_unused(mac, r),"tx ring full"); |
|---|
| 211 | return (ag7100_ndesc_unused(mac, r) < tx_max_desc_per_ds_pkt + 2); |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | |
|---|
| 215 | static int |
|---|
| 216 | ag7100_open(struct net_device *dev) |
|---|
| 217 | { |
|---|
| 218 | unsigned int w1 = 0, w2 = 0; |
|---|
| 219 | ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; |
|---|
| 220 | int st; |
|---|
| 221 | #if defined(CONFIG_AR9100) && defined(SWITCH_AHB_FREQ) |
|---|
| 222 | u32 tmp_pll, pll; |
|---|
| 223 | #endif |
|---|
| 224 | |
|---|
| 225 | assert(mac); |
|---|
| 226 | |
|---|
| 227 | st = request_irq(mac->mac_irq, ag7100_intr, 0, dev->name, dev); |
|---|
| 228 | if (st < 0) |
|---|
| 229 | { |
|---|
| 230 | printk(MODULE_NAME ": request irq %d failed %d\n", mac->mac_irq, st); |
|---|
| 231 | return 1; |
|---|
| 232 | } |
|---|
| 233 | if (ag7100_tx_alloc(mac)) goto tx_failed; |
|---|
| 234 | if (ag7100_rx_alloc(mac)) goto rx_failed; |
|---|
| 235 | |
|---|
| 236 | ag7100_hw_setup(mac); |
|---|
| 237 | #if defined(CONFIG_AR9100) && defined(SWITCH_AHB_FREQ) |
|---|
| 238 | /* |
|---|
| 239 | * Reduce the AHB frequency to 100MHz while setting up the |
|---|
| 240 | * S26 phy. |
|---|
| 241 | */ |
|---|
| 242 | pll= ar7100_reg_rd(AR7100_PLL_CONFIG); |
|---|
| 243 | tmp_pll = pll& ~((PLL_DIV_MASK << PLL_DIV_SHIFT) | (PLL_REF_DIV_MASK << PLL_REF_DIV_SHIFT)); |
|---|
| 244 | tmp_pll = tmp_pll | (0x64 << PLL_DIV_SHIFT) | |
|---|
| 245 | (0x5 << PLL_REF_DIV_SHIFT) | (1 << AHB_DIV_SHIFT); |
|---|
| 246 | |
|---|
| 247 | ar7100_reg_wr_nf(AR7100_PLL_CONFIG, tmp_pll); |
|---|
| 248 | udelay(100*1000); |
|---|
| 249 | #endif |
|---|
| 250 | |
|---|
| 251 | #if defined(CONFIG_ATHRS26_PHY) |
|---|
| 252 | /* if using header for register configuration, we have to */ |
|---|
| 253 | /* configure s26 register after frame transmission is enabled */ |
|---|
| 254 | if (mac->mac_unit == 1) /* wan phy */ |
|---|
| 255 | athrs26_reg_init(); |
|---|
| 256 | #elif defined(CONFIG_ATHRS16_PHY) |
|---|
| 257 | if (mac->mac_unit == 1) |
|---|
| 258 | athrs16_reg_init(); |
|---|
| 259 | #endif |
|---|
| 260 | |
|---|
| 261 | ag7100_phy_setup(mac->mac_unit); |
|---|
| 262 | |
|---|
| 263 | #if defined(CONFIG_AR9100) && defined(SWITCH_AHB_FREQ) |
|---|
| 264 | ar7100_reg_wr_nf(AR7100_PLL_CONFIG, pll); |
|---|
| 265 | udelay(100*1000); |
|---|
| 266 | #endif |
|---|
| 267 | /* |
|---|
| 268 | * set the mac addr |
|---|
| 269 | */ |
|---|
| 270 | addr_to_words(dev->dev_addr, w1, w2); |
|---|
| 271 | ag7100_reg_wr(mac, AG7100_GE_MAC_ADDR1, w1); |
|---|
| 272 | ag7100_reg_wr(mac, AG7100_GE_MAC_ADDR2, w2); |
|---|
| 273 | |
|---|
| 274 | /* |
|---|
| 275 | * phy link mgmt |
|---|
| 276 | */ |
|---|
| 277 | rx_hang_detect_pkt_cnt_all[mac->mac_unit] = ag7100_get_rx_count(mac); |
|---|
| 278 | rx_hang_detect_pkt_cnt_valid[mac->mac_unit] = mac->net_rx_packets; |
|---|
| 279 | rx_hang_detected[mac->mac_unit] = 0; |
|---|
| 280 | |
|---|
| 281 | init_timer(&mac->mac_phy_timer); |
|---|
| 282 | mac->mac_phy_timer.data = (unsigned long)mac; |
|---|
| 283 | mac->mac_phy_timer.function = ag7100_check_link; |
|---|
| 284 | ag7100_check_link(mac); |
|---|
| 285 | |
|---|
| 286 | dev->trans_start = jiffies; |
|---|
| 287 | |
|---|
| 288 | napi_enable(&mac->mac_napi); |
|---|
| 289 | ag7100_int_enable(mac); |
|---|
| 290 | ag7100_rx_start(mac); |
|---|
| 291 | netif_start_queue(dev); |
|---|
| 292 | |
|---|
| 293 | ag7100_start_rx_count(mac); |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | |
|---|
| 297 | return 0; |
|---|
| 298 | |
|---|
| 299 | rx_failed: |
|---|
| 300 | ag7100_tx_free(mac); |
|---|
| 301 | tx_failed: |
|---|
| 302 | free_irq(mac->mac_irq, dev); |
|---|
| 303 | return 1; |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | static int |
|---|
| 307 | ag7100_stop(struct net_device *dev) |
|---|
| 308 | { |
|---|
| 309 | ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; |
|---|
| 310 | int flags; |
|---|
| 311 | |
|---|
| 312 | spin_lock_irqsave(&mac->mac_lock, flags); |
|---|
| 313 | napi_disable(&mac->mac_napi); |
|---|
| 314 | netif_stop_queue(dev); |
|---|
| 315 | netif_carrier_off(dev); |
|---|
| 316 | |
|---|
| 317 | ag7100_hw_stop(mac); |
|---|
| 318 | free_irq(mac->mac_irq, dev); |
|---|
| 319 | |
|---|
| 320 | /* |
|---|
| 321 | * WAR for bug:32681 reduces the no of TX buffers to five from the |
|---|
| 322 | * actual number of allocated buffers. Revert the value before freeing |
|---|
| 323 | * them to avoid memory leak |
|---|
| 324 | */ |
|---|
| 325 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 326 | mac->mac_txring.ring_nelem = AG7100_TX_DESC_CNT; |
|---|
| 327 | mac->speed_10t = 0; |
|---|
| 328 | #endif |
|---|
| 329 | |
|---|
| 330 | ag7100_tx_free(mac); |
|---|
| 331 | ag7100_rx_free(mac); |
|---|
| 332 | |
|---|
| 333 | |
|---|
| 334 | del_timer(&mac->mac_phy_timer); |
|---|
| 335 | spin_unlock_irqrestore(&mac->mac_lock, flags); |
|---|
| 336 | |
|---|
| 337 | /*ag7100_trc_dump();*/ |
|---|
| 338 | return 0; |
|---|
| 339 | } |
|---|
| 340 | |
|---|
| 341 | #define FIFO_CFG0_WTM BIT(0) /* Watermark Module */ |
|---|
| 342 | #define FIFO_CFG0_RXS BIT(1) /* Rx System Module */ |
|---|
| 343 | #define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */ |
|---|
| 344 | #define FIFO_CFG0_TXS BIT(3) /* Tx System Module */ |
|---|
| 345 | #define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */ |
|---|
| 346 | #define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \ |
|---|
| 347 | | FIFO_CFG0_TXS | FIFO_CFG0_TXF) |
|---|
| 348 | |
|---|
| 349 | #define FIFO_CFG0_ENABLE_SHIFT 8 |
|---|
| 350 | |
|---|
| 351 | #define FIFO_CFG4_DE BIT(0) /* Drop Event */ |
|---|
| 352 | #define FIFO_CFG4_DV BIT(1) /* RX_DV Event */ |
|---|
| 353 | #define FIFO_CFG4_FC BIT(2) /* False Carrier */ |
|---|
| 354 | #define FIFO_CFG4_CE BIT(3) /* Code Error */ |
|---|
| 355 | #define FIFO_CFG4_CR BIT(4) /* CRC error */ |
|---|
| 356 | #define FIFO_CFG4_LM BIT(5) /* Length Mismatch */ |
|---|
| 357 | #define FIFO_CFG4_LO BIT(6) /* Length out of range */ |
|---|
| 358 | #define FIFO_CFG4_OK BIT(7) /* Packet is OK */ |
|---|
| 359 | #define FIFO_CFG4_MC BIT(8) /* Multicast Packet */ |
|---|
| 360 | #define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */ |
|---|
| 361 | #define FIFO_CFG4_DR BIT(10) /* Dribble */ |
|---|
| 362 | #define FIFO_CFG4_LE BIT(11) /* Long Event */ |
|---|
| 363 | #define FIFO_CFG4_CF BIT(12) /* Control Frame */ |
|---|
| 364 | #define FIFO_CFG4_PF BIT(13) /* Pause Frame */ |
|---|
| 365 | #define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */ |
|---|
| 366 | #define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */ |
|---|
| 367 | #define FIFO_CFG4_FT BIT(16) /* Frame Truncated */ |
|---|
| 368 | #define FIFO_CFG4_UC BIT(17) /* Unicast Packet */ |
|---|
| 369 | |
|---|
| 370 | #define FIFO_CFG5_DE BIT(0) /* Drop Event */ |
|---|
| 371 | #define FIFO_CFG5_DV BIT(1) /* RX_DV Event */ |
|---|
| 372 | #define FIFO_CFG5_FC BIT(2) /* False Carrier */ |
|---|
| 373 | #define FIFO_CFG5_CE BIT(3) /* Code Error */ |
|---|
| 374 | #define FIFO_CFG5_LM BIT(4) /* Length Mismatch */ |
|---|
| 375 | #define FIFO_CFG5_LO BIT(5) /* Length Out of Range */ |
|---|
| 376 | #define FIFO_CFG5_OK BIT(6) /* Packet is OK */ |
|---|
| 377 | #define FIFO_CFG5_MC BIT(7) /* Multicast Packet */ |
|---|
| 378 | #define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */ |
|---|
| 379 | #define FIFO_CFG5_DR BIT(9) /* Dribble */ |
|---|
| 380 | #define FIFO_CFG5_CF BIT(10) /* Control Frame */ |
|---|
| 381 | #define FIFO_CFG5_PF BIT(11) /* Pause Frame */ |
|---|
| 382 | #define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */ |
|---|
| 383 | #define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */ |
|---|
| 384 | #define FIFO_CFG5_LE BIT(14) /* Long Event */ |
|---|
| 385 | #define FIFO_CFG5_FT BIT(15) /* Frame Truncated */ |
|---|
| 386 | #define FIFO_CFG5_16 BIT(16) /* unknown */ |
|---|
| 387 | #define FIFO_CFG5_17 BIT(17) /* unknown */ |
|---|
| 388 | #define FIFO_CFG5_SF BIT(18) /* Short Frame */ |
|---|
| 389 | #define FIFO_CFG5_BM BIT(19) /* Byte Mode */ |
|---|
| 390 | |
|---|
| 391 | |
|---|
| 392 | #define FIFO_CFG0_INIT (FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT) |
|---|
| 393 | |
|---|
| 394 | #define FIFO_CFG4_INIT (FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \ |
|---|
| 395 | FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \ |
|---|
| 396 | FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \ |
|---|
| 397 | FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \ |
|---|
| 398 | FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \ |
|---|
| 399 | FIFO_CFG4_VT) |
|---|
| 400 | |
|---|
| 401 | #define FIFO_CFG5_INIT (FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \ |
|---|
| 402 | FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \ |
|---|
| 403 | FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \ |
|---|
| 404 | FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \ |
|---|
| 405 | FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \ |
|---|
| 406 | FIFO_CFG5_17 | FIFO_CFG5_SF) |
|---|
| 407 | |
|---|
| 408 | |
|---|
| 409 | static void |
|---|
| 410 | ag7100_hw_setup(ag7100_mac_t *mac) |
|---|
| 411 | { |
|---|
| 412 | ag7100_ring_t *tx = &mac->mac_txring, *rx = &mac->mac_rxring; |
|---|
| 413 | ag7100_desc_t *r0, *t0; |
|---|
| 414 | #ifdef CONFIG_AR9100 |
|---|
| 415 | #ifndef CONFIG_PORT0_AS_SWITCH |
|---|
| 416 | if(mac->mac_unit) { |
|---|
| 417 | #ifdef CONFIG_DUAL_F1E_PHY |
|---|
| 418 | ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | |
|---|
| 419 | AG7100_MAC_CFG1_TX_EN|AG7100_MAC_CFG1_RX_FCTL)); |
|---|
| 420 | #else |
|---|
| 421 | ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | |
|---|
| 422 | AG7100_MAC_CFG1_TX_EN|AG7100_MAC_CFG1_RX_FCTL|AG7100_MAC_CFG1_TX_FCTL)); |
|---|
| 423 | #endif |
|---|
| 424 | } |
|---|
| 425 | else { |
|---|
| 426 | ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | |
|---|
| 427 | AG7100_MAC_CFG1_TX_EN|AG7100_MAC_CFG1_RX_FCTL)); |
|---|
| 428 | } |
|---|
| 429 | #else |
|---|
| 430 | if(mac->mac_unit) { |
|---|
| 431 | ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | |
|---|
| 432 | AG7100_MAC_CFG1_TX_EN|AG7100_MAC_CFG1_RX_FCTL)); |
|---|
| 433 | } |
|---|
| 434 | else { |
|---|
| 435 | ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | |
|---|
| 436 | AG7100_MAC_CFG1_TX_EN |AG7100_MAC_CFG1_RX_FCTL|AG7100_MAC_CFG1_TX_FCTL)); |
|---|
| 437 | } |
|---|
| 438 | #endif |
|---|
| 439 | #else |
|---|
| 440 | ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | |
|---|
| 441 | AG7100_MAC_CFG1_TX_EN)); |
|---|
| 442 | #endif |
|---|
| 443 | ag7100_reg_rmw_set(mac, AG7100_MAC_CFG2, (AG7100_MAC_CFG2_PAD_CRC_EN | |
|---|
| 444 | AG7100_MAC_CFG2_LEN_CHECK)); |
|---|
| 445 | ag7100_reg_wr(mac, AG71XX_REG_MAC_MFL, AG71XX_TX_MTU_LEN); |
|---|
| 446 | |
|---|
| 447 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_0, FIFO_CFG0_INIT); |
|---|
| 448 | /* |
|---|
| 449 | * set the mii if type - NB reg not in the gigE space |
|---|
| 450 | */ |
|---|
| 451 | ar7100_reg_wr(mii_reg(mac), mii_if(mac)); |
|---|
| 452 | ag7100_reg_wr(mac, AG7100_MAC_MII_MGMT_CFG, AG7100_MGMT_CFG_CLK_DIV_20); |
|---|
| 453 | |
|---|
| 454 | #ifdef CONFIG_AR7100_EMULATION |
|---|
| 455 | ag7100_reg_rmw_set(mac, AG7100_MAC_FIFO_CFG_4, 0x3ffff); |
|---|
| 456 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_1, 0xfff0000); |
|---|
| 457 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_2, 0x1fff); |
|---|
| 458 | #else |
|---|
| 459 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_1, 0xfff0000); |
|---|
| 460 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_2, 0x1fff); |
|---|
| 461 | /* |
|---|
| 462 | * Weed out junk frames (CRC errored, short collision'ed frames etc.) |
|---|
| 463 | */ |
|---|
| 464 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_4, FIFO_CFG4_INIT); |
|---|
| 465 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_5, FIFO_CFG5_INIT); |
|---|
| 466 | #endif |
|---|
| 467 | |
|---|
| 468 | t0 = &tx->ring_desc[0]; |
|---|
| 469 | r0 = &rx->ring_desc[0]; |
|---|
| 470 | |
|---|
| 471 | ag7100_reg_wr(mac, AG7100_DMA_TX_DESC, ag7100_desc_dma_addr(tx, t0)); |
|---|
| 472 | ag7100_reg_wr(mac, AG7100_DMA_RX_DESC, ag7100_desc_dma_addr(rx, r0)); |
|---|
| 473 | |
|---|
| 474 | printk(MODULE_NAME ": cfg1 %#x cfg2 %#x\n", ag7100_reg_rd(mac, AG7100_MAC_CFG1), |
|---|
| 475 | ag7100_reg_rd(mac, AG7100_MAC_CFG2)); |
|---|
| 476 | } |
|---|
| 477 | |
|---|
| 478 | static void |
|---|
| 479 | ag7100_hw_stop(ag7100_mac_t *mac) |
|---|
| 480 | { |
|---|
| 481 | ag7100_rx_stop(mac); |
|---|
| 482 | ag7100_tx_stop(mac); |
|---|
| 483 | ag7100_int_disable(mac); |
|---|
| 484 | /* |
|---|
| 485 | * put everything into reset. |
|---|
| 486 | */ |
|---|
| 487 | #ifdef CONFIG_DUAL_F1E_PHY |
|---|
| 488 | if(mac->mac_unit == 1) |
|---|
| 489 | #endif |
|---|
| 490 | ag7100_reg_rmw_set(mac, AG7100_MAC_CFG1, AG7100_MAC_CFG1_SOFT_RST); |
|---|
| 491 | } |
|---|
| 492 | |
|---|
| 493 | /* |
|---|
| 494 | * program the usb pll (misnomer) to genrate appropriate clock |
|---|
| 495 | * Write 2 into control field |
|---|
| 496 | * Write pll value |
|---|
| 497 | * Write 3 into control field |
|---|
| 498 | * Write 0 into control field |
|---|
| 499 | */ |
|---|
| 500 | #ifdef CONFIG_AR9100 |
|---|
| 501 | #define ag7100_pll_shift(_mac) (((_mac)->mac_unit) ? 22: 20) |
|---|
| 502 | #define ag7100_pll_offset(_mac) \ |
|---|
| 503 | (((_mac)->mac_unit) ? AR9100_ETH_INT1_CLK : \ |
|---|
| 504 | AR9100_ETH_INT0_CLK) |
|---|
| 505 | #else |
|---|
| 506 | #define ag7100_pll_shift(_mac) (((_mac)->mac_unit) ? 19: 17) |
|---|
| 507 | #define ag7100_pll_offset(_mac) \ |
|---|
| 508 | (((_mac)->mac_unit) ? AR7100_USB_PLL_GE1_OFFSET : \ |
|---|
| 509 | AR7100_USB_PLL_GE0_OFFSET) |
|---|
| 510 | #endif |
|---|
| 511 | static void |
|---|
| 512 | ag7100_set_pll(ag7100_mac_t *mac, unsigned int pll) |
|---|
| 513 | { |
|---|
| 514 | #ifdef CONFIG_AR9100 |
|---|
| 515 | #define ETH_PLL_CONFIG AR9100_ETH_PLL_CONFIG |
|---|
| 516 | #else |
|---|
| 517 | #define ETH_PLL_CONFIG AR7100_USB_PLL_CONFIG |
|---|
| 518 | #endif |
|---|
| 519 | uint32_t shift, reg, val; |
|---|
| 520 | |
|---|
| 521 | shift = ag7100_pll_shift(mac); |
|---|
| 522 | reg = ag7100_pll_offset(mac); |
|---|
| 523 | |
|---|
| 524 | val = ar7100_reg_rd(ETH_PLL_CONFIG); |
|---|
| 525 | val &= ~(3 << shift); |
|---|
| 526 | val |= (2 << shift); |
|---|
| 527 | ar7100_reg_wr(ETH_PLL_CONFIG, val); |
|---|
| 528 | udelay(100); |
|---|
| 529 | |
|---|
| 530 | ar7100_reg_wr(reg, pll); |
|---|
| 531 | |
|---|
| 532 | val |= (3 << shift); |
|---|
| 533 | ar7100_reg_wr(ETH_PLL_CONFIG, val); |
|---|
| 534 | udelay(100); |
|---|
| 535 | |
|---|
| 536 | val &= ~(3 << shift); |
|---|
| 537 | ar7100_reg_wr(ETH_PLL_CONFIG, val); |
|---|
| 538 | udelay(100); |
|---|
| 539 | |
|---|
| 540 | printk(MODULE_NAME ": pll reg %#x: %#x ", reg, ar7100_reg_rd(reg)); |
|---|
| 541 | } |
|---|
| 542 | |
|---|
| 543 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 544 | |
|---|
| 545 | |
|---|
| 546 | /* |
|---|
| 547 | * Flush from tail till the head and free all the socket buffers even if owned by DMA |
|---|
| 548 | * before we change the size of the ring buffer to avoid memory leaks and reset the ring buffer. |
|---|
| 549 | * |
|---|
| 550 | * WAR for Bug: 32681 |
|---|
| 551 | */ |
|---|
| 552 | |
|---|
| 553 | void |
|---|
| 554 | ag7100_tx_flush(ag7100_mac_t *mac) |
|---|
| 555 | { |
|---|
| 556 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 557 | int head = r->ring_nelem , tail = 0, flushed = 0, i; |
|---|
| 558 | ag7100_desc_t *ds; |
|---|
| 559 | ag7100_buffer_t *bf; |
|---|
| 560 | uint32_t flags; |
|---|
| 561 | |
|---|
| 562 | |
|---|
| 563 | ar7100_flush_ge(mac->mac_unit); |
|---|
| 564 | |
|---|
| 565 | while(flushed != head) |
|---|
| 566 | { |
|---|
| 567 | ds = &r->ring_desc[tail]; |
|---|
| 568 | |
|---|
| 569 | bf = &r->ring_buffer[tail]; |
|---|
| 570 | if(bf->buf_pkt) { |
|---|
| 571 | for(i = 0; i < bf->buf_nds; i++) |
|---|
| 572 | { |
|---|
| 573 | ag7100_intr_ack_tx(mac); |
|---|
| 574 | ag7100_ring_incr(tail); |
|---|
| 575 | } |
|---|
| 576 | |
|---|
| 577 | ag7100_buffer_free(bf->buf_pkt); |
|---|
| 578 | bf->buf_pkt = NULL; |
|---|
| 579 | } |
|---|
| 580 | else |
|---|
| 581 | ag7100_ring_incr(tail); |
|---|
| 582 | |
|---|
| 583 | ag7100_tx_own(ds); |
|---|
| 584 | flushed ++; |
|---|
| 585 | } |
|---|
| 586 | r->ring_head = r->ring_tail = 0; |
|---|
| 587 | |
|---|
| 588 | return; |
|---|
| 589 | } |
|---|
| 590 | |
|---|
| 591 | /* |
|---|
| 592 | * Work around to recover from Tx failure when connected to 10BASET. |
|---|
| 593 | * Bug: 32681. |
|---|
| 594 | * |
|---|
| 595 | * After AutoNeg to 10Mbps Half Duplex, under some un-identified circumstances |
|---|
| 596 | * during the init sequence, the MAC is in some illegal state |
|---|
| 597 | * that stops the TX and hence no TXCTL to the PHY. |
|---|
| 598 | * On Tx Timeout from the software, the reset sequence is done again which recovers the |
|---|
| 599 | * MAC and Tx goes through without any problem. |
|---|
| 600 | * Instead of waiting for the application to transmit and recover, we transmit |
|---|
| 601 | * 40 dummy Tx pkts on negogiating as 10BASET. |
|---|
| 602 | * Reduce the number of TX buffers from 40 to 5 so that in case of TX failures we do |
|---|
| 603 | * a immediate reset and retrasmit again till we successfully transmit all of them. |
|---|
| 604 | */ |
|---|
| 605 | |
|---|
| 606 | void |
|---|
| 607 | howl_10baset_war(ag7100_mac_t *mac) |
|---|
| 608 | { |
|---|
| 609 | |
|---|
| 610 | struct sk_buff *dummy_pkt; |
|---|
| 611 | struct net_device *dev = mac->mac_dev; |
|---|
| 612 | ag7100_desc_t *ds; |
|---|
| 613 | ag7100_ring_t *r; |
|---|
| 614 | int i=6; |
|---|
| 615 | |
|---|
| 616 | /* |
|---|
| 617 | * Create dummy packet |
|---|
| 618 | */ |
|---|
| 619 | dummy_pkt = dev_alloc_skb(64); |
|---|
| 620 | skb_put(dummy_pkt, 60); |
|---|
| 621 | atomic_dec(&dummy_pkt->users); |
|---|
| 622 | while(--i >= 0) { |
|---|
| 623 | dummy_pkt->data[i] = 0xff; |
|---|
| 624 | } |
|---|
| 625 | ag7100_get_default_macaddr(mac,(dummy_pkt->data + 6)); |
|---|
| 626 | dummy_pkt->dev = dev; |
|---|
| 627 | i = 40; |
|---|
| 628 | |
|---|
| 629 | /* |
|---|
| 630 | * Reduce the no of TX buffers to five from the actual number |
|---|
| 631 | * of allocated buffers and link the fifth descriptor to first. |
|---|
| 632 | * WAR for Bug:32681 to cause early Tx Timeout in 10BASET. |
|---|
| 633 | */ |
|---|
| 634 | ag7100_tx_flush(mac); |
|---|
| 635 | ds = mac->mac_txring.ring_desc; |
|---|
| 636 | r = &mac->mac_txring; |
|---|
| 637 | r->ring_nelem = 5; |
|---|
| 638 | ds[r->ring_nelem - 1].next_desc = ag7100_desc_dma_addr(r, &ds[0]); |
|---|
| 639 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_3, 0x300020); |
|---|
| 640 | |
|---|
| 641 | mac->speed_10t = 1; |
|---|
| 642 | while(i-- && mac->speed_10t) { |
|---|
| 643 | netif_carrier_on(dev); |
|---|
| 644 | |
|---|
| 645 | mdelay(100); |
|---|
| 646 | ag7100_hard_start(dummy_pkt,dev); |
|---|
| 647 | |
|---|
| 648 | netif_carrier_off(dev); |
|---|
| 649 | } |
|---|
| 650 | return ; |
|---|
| 651 | } |
|---|
| 652 | #endif |
|---|
| 653 | |
|---|
| 654 | /* |
|---|
| 655 | * Several fields need to be programmed based on what the PHY negotiated |
|---|
| 656 | * Ideally we should quiesce everything before touching the pll, but: |
|---|
| 657 | * 1. If its a linkup/linkdown, we dont care about quiescing the traffic. |
|---|
| 658 | * 2. If its a single gigE PHY, this can only happen on lup/ldown. |
|---|
| 659 | * 3. If its a 100Mpbs switch, the link will always remain at 100 (or nothing) |
|---|
| 660 | * 4. If its a gigE switch then the speed should always be set at 1000Mpbs, |
|---|
| 661 | * and the switch should provide buffering for slower devices. |
|---|
| 662 | * |
|---|
| 663 | * XXX Only gigE PLL can be changed as a parameter for now. 100/10 is hardcoded. |
|---|
| 664 | * XXX Need defines for them - |
|---|
| 665 | * XXX FIFO settings based on the mode |
|---|
| 666 | */ |
|---|
| 667 | #ifdef CONFIG_ATHRS16_PHY |
|---|
| 668 | static int is_setup_done = 0; |
|---|
| 669 | #endif |
|---|
| 670 | static void |
|---|
| 671 | ag7100_set_mac_from_link(ag7100_mac_t *mac, ag7100_phy_speed_t speed, int fdx) |
|---|
| 672 | { |
|---|
| 673 | #ifdef CONFIG_ATHRS26_PHY |
|---|
| 674 | int change_flag = 0; |
|---|
| 675 | |
|---|
| 676 | if(mac->mac_speed != speed) |
|---|
| 677 | change_flag = 1; |
|---|
| 678 | |
|---|
| 679 | if(change_flag) |
|---|
| 680 | { |
|---|
| 681 | athrs26_phy_off(mac); |
|---|
| 682 | athrs26_mac_speed_set(mac, speed); |
|---|
| 683 | } |
|---|
| 684 | #endif |
|---|
| 685 | #ifdef CONFIG_ATHRS16_PHY |
|---|
| 686 | if(!is_setup_done && |
|---|
| 687 | #ifndef CONFIG_PORT0_AS_SWITCH |
|---|
| 688 | mac->mac_unit == 0 && |
|---|
| 689 | #else |
|---|
| 690 | mac->mac_unit == 1 && |
|---|
| 691 | #endif |
|---|
| 692 | (mac->mac_speed != speed || mac->mac_fdx != fdx)) |
|---|
| 693 | { |
|---|
| 694 | /* workaround for PHY4 port thru RGMII */ |
|---|
| 695 | phy_mode_setup(); |
|---|
| 696 | is_setup_done = 1; |
|---|
| 697 | } |
|---|
| 698 | #endif |
|---|
| 699 | /* |
|---|
| 700 | * Flush TX descriptors , reset the MAC and relink all descriptors. |
|---|
| 701 | * WAR for Bug:32681 |
|---|
| 702 | */ |
|---|
| 703 | |
|---|
| 704 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 705 | if(mac->speed_10t && (speed != AG7100_PHY_SPEED_10T)) { |
|---|
| 706 | mac->speed_10t = 0; |
|---|
| 707 | ag7100_tx_flush(mac); |
|---|
| 708 | mdelay(500); |
|---|
| 709 | ag7100_dma_reset(mac); |
|---|
| 710 | } |
|---|
| 711 | #endif |
|---|
| 712 | |
|---|
| 713 | mac->mac_speed = speed; |
|---|
| 714 | mac->mac_fdx = fdx; |
|---|
| 715 | |
|---|
| 716 | ag7100_set_mii_ctrl_speed(mac, speed); |
|---|
| 717 | ag7100_set_mac_duplex(mac, fdx); |
|---|
| 718 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_3, fifo_3); |
|---|
| 719 | #ifndef CONFIG_AR9100 |
|---|
| 720 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_5, fifo_5); |
|---|
| 721 | #endif |
|---|
| 722 | |
|---|
| 723 | switch (speed) |
|---|
| 724 | { |
|---|
| 725 | case AG7100_PHY_SPEED_1000T: |
|---|
| 726 | #ifdef CONFIG_AR9100 |
|---|
| 727 | ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_3, 0x780fff); |
|---|
| 728 | #endif |
|---|
| 729 | ag7100_set_mac_if(mac, 1); |
|---|
| 730 | #ifdef CONFIG_AR9100 |
|---|
| 731 | #ifdef CONFIG_BUFFALO |
|---|
| 732 | ag7100_set_pll(mac, e1000_pll[mac->mac_unit ? 1 : 0]); |
|---|
| 733 | #else |
|---|
| 734 | if (mac->mac_unit == 0) |
|---|
| 735 | { /* eth0 */ |
|---|
| 736 | ag7100_set_pll(mac, gige_pll); |
|---|
| 737 | } |
|---|
| 738 | else |
|---|
| 739 | { |
|---|
| 740 | #ifdef CONFIG_DUAL_F1E_PHY |
|---|
| 741 | ag7100_set_pll(mac, gige_pll); |
|---|
| 742 | #else |
|---|
| 743 | ag7100_set_pll(mac, SW_PLL); |
|---|
| 744 | #endif |
|---|
| 745 | } |
|---|
| 746 | #endif |
|---|
| 747 | #else |
|---|
| 748 | |
|---|
| 749 | #ifdef CONFIG_BUFFALO |
|---|
| 750 | ag7100_set_pll(mac, e1000_pll[mac->mac_unit ? 1 : 0]); |
|---|
| 751 | #else |
|---|
| 752 | ag7100_set_pll(mac, gige_pll); |
|---|
| 753 | #endif |
|---|
| 754 | #endif |
|---|
| 755 | ag7100_reg_rmw_set(mac, AG7100_MAC_FIFO_CFG_5, (1 << 19)); |
|---|
| 756 | break; |
|---|
| 757 | |
|---|
| 758 | case AG7100_PHY_SPEED_100TX: |
|---|
| 759 | ag7100_set_mac_if(mac, 0); |
|---|
| 760 | ag7100_set_mac_speed(mac, 1); |
|---|
| 761 | #ifndef CONFIG_AR7100_EMULATION |
|---|
| 762 | #ifdef CONFIG_AR9100 |
|---|
| 763 | #ifdef CONFIG_BUFFALO |
|---|
| 764 | ag7100_set_pll(mac, e100_pll[mac->mac_unit ? 1 : 0]); |
|---|
| 765 | #else |
|---|
| 766 | if (mac->mac_unit == 0) |
|---|
| 767 | { /* eth0 */ |
|---|
| 768 | ag7100_set_pll(mac, 0x13000a44); |
|---|
| 769 | } |
|---|
| 770 | else |
|---|
| 771 | { |
|---|
| 772 | #ifdef CONFIG_DUAL_F1E_PHY |
|---|
| 773 | ag7100_set_pll(mac, 0x13000a44); |
|---|
| 774 | #else |
|---|
| 775 | ag7100_set_pll(mac, SW_PLL); |
|---|
| 776 | #endif |
|---|
| 777 | } |
|---|
| 778 | #endif |
|---|
| 779 | #else |
|---|
| 780 | #ifdef CONFIG_BUFFALO |
|---|
| 781 | ag7100_set_pll(mac, e100_pll[mac->mac_unit ? 1 : 0]); |
|---|
| 782 | #else |
|---|
| 783 | #ifdef CONFIG_CAMEO_REALTEK_PHY |
|---|
| 784 | ag7100_set_pll(mac, 0x0001099); |
|---|
| 785 | #else |
|---|
| 786 | ag7100_set_pll(mac, 0x0001099); |
|---|
| 787 | #endif |
|---|
| 788 | #endif |
|---|
| 789 | #endif |
|---|
| 790 | #endif |
|---|
| 791 | ag7100_reg_rmw_clear(mac, AG7100_MAC_FIFO_CFG_5, (1 << 19)); |
|---|
| 792 | break; |
|---|
| 793 | |
|---|
| 794 | case AG7100_PHY_SPEED_10T: |
|---|
| 795 | ag7100_set_mac_if(mac, 0); |
|---|
| 796 | ag7100_set_mac_speed(mac, 0); |
|---|
| 797 | #ifdef CONFIG_AR9100 |
|---|
| 798 | #ifdef CONFIG_BUFFALO |
|---|
| 799 | ag7100_set_pll(mac, e10_pll[mac->mac_unit ? 1 : 0]); |
|---|
| 800 | #else |
|---|
| 801 | if (mac->mac_unit == 0) |
|---|
| 802 | { /* eth0 */ |
|---|
| 803 | ag7100_set_pll(mac, 0x00441099); |
|---|
| 804 | } |
|---|
| 805 | else |
|---|
| 806 | { |
|---|
| 807 | #ifdef CONFIG_DUAL_F1E_PHY |
|---|
| 808 | ag7100_set_pll(mac, 0x00441099); |
|---|
| 809 | #else |
|---|
| 810 | ag7100_set_pll(mac, SW_PLL); |
|---|
| 811 | #endif |
|---|
| 812 | } |
|---|
| 813 | #endif |
|---|
| 814 | #else |
|---|
| 815 | #ifdef CONFIG_BUFFALO |
|---|
| 816 | ag7100_set_pll(mac, e10_pll[mac->mac_unit ? 1 : 0]); |
|---|
| 817 | #else |
|---|
| 818 | #ifdef CONFIG_CAMEO_REALTEK_PHY |
|---|
| 819 | ag7100_set_pll(mac, 0x00991099); |
|---|
| 820 | #else |
|---|
| 821 | ag7100_set_pll(mac, 0x00991099); |
|---|
| 822 | #endif |
|---|
| 823 | #endif |
|---|
| 824 | #endif |
|---|
| 825 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 826 | if((speed == AG7100_PHY_SPEED_10T) && !mac->speed_10t) { |
|---|
| 827 | howl_10baset_war(mac); |
|---|
| 828 | } |
|---|
| 829 | #endif |
|---|
| 830 | ag7100_reg_rmw_clear(mac, AG7100_MAC_FIFO_CFG_5, (1 << 19)); |
|---|
| 831 | break; |
|---|
| 832 | |
|---|
| 833 | default: |
|---|
| 834 | assert(0); |
|---|
| 835 | } |
|---|
| 836 | |
|---|
| 837 | #ifdef CONFIG_ATHRS26_PHY |
|---|
| 838 | if(change_flag) |
|---|
| 839 | athrs26_phy_on(mac); |
|---|
| 840 | #endif |
|---|
| 841 | |
|---|
| 842 | printk(MODULE_NAME ": CPU PhaseLockLoop : %#x\n", *(volatile int *) 0xb8050000); //set CPU PhaseLockLoop configuration |
|---|
| 843 | printk(MODULE_NAME ": Secondary PhaseLockLoop: %#x\n", *(volatile int *) 0xb8050004); //set secondary PhaseLockLoop configuration |
|---|
| 844 | printk(MODULE_NAME ": Ethernet Internal Clock Control: %#x\n", *(volatile int *) 0xb8050010); //set Ethernet Internal Clock Control |
|---|
| 845 | printk(MODULE_NAME ": mii: %#x\n", ar7100_reg_rd(mii_reg(mac))); |
|---|
| 846 | printk(MODULE_NAME ": cfg1: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_CFG1)); |
|---|
| 847 | printk(MODULE_NAME ": cfg2: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_CFG2)); |
|---|
| 848 | printk(MODULE_NAME ": fcfg_0: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_0)); |
|---|
| 849 | printk(MODULE_NAME ": fcfg_1: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_1)); |
|---|
| 850 | printk(MODULE_NAME ": fcfg_2: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_2)); |
|---|
| 851 | printk(MODULE_NAME ": fcfg_3: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_3)); |
|---|
| 852 | printk(MODULE_NAME ": fcfg_4: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_4)); |
|---|
| 853 | printk(MODULE_NAME ": fcfg_5: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_5)); |
|---|
| 854 | } |
|---|
| 855 | |
|---|
| 856 | static void copy_txdescs(ag7100_mac_t *mac, int start, int end) |
|---|
| 857 | { |
|---|
| 858 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 859 | ag7100_ring_t *tr = &mac->mac_txring_cache; |
|---|
| 860 | ag7100_desc_t *tds, *fds; |
|---|
| 861 | |
|---|
| 862 | if (end >= r->ring_nelem) end -= r->ring_nelem; |
|---|
| 863 | while (start != end) |
|---|
| 864 | { |
|---|
| 865 | fds = &r->ring_desc[start]; |
|---|
| 866 | tds = &tr->ring_desc[start]; |
|---|
| 867 | memcpy(tds, fds, 8); /* just the first two words of the desc */ |
|---|
| 868 | ag7100_ring_incr(start); |
|---|
| 869 | } |
|---|
| 870 | } |
|---|
| 871 | |
|---|
| 872 | static int check_for_dma_hang(ag7100_mac_t *mac) { |
|---|
| 873 | |
|---|
| 874 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 875 | int head = r->ring_head, tail = r->ring_tail; |
|---|
| 876 | ag7100_desc_t *ds; |
|---|
| 877 | #if 1//DMA tx hang |
|---|
| 878 | ag7100_buffer_t *bf; |
|---|
| 879 | #endif |
|---|
| 880 | ag7100_buffer_t *bp; |
|---|
| 881 | |
|---|
| 882 | ar7100_flush_ge(mac->mac_unit); |
|---|
| 883 | |
|---|
| 884 | while (tail != head) |
|---|
| 885 | { |
|---|
| 886 | ds = &r->ring_desc[tail]; |
|---|
| 887 | bp = &r->ring_buffer[tail]; |
|---|
| 888 | |
|---|
| 889 | if(ag7100_tx_owned_by_dma(ds)) { |
|---|
| 890 | if ((jiffies - bp->trans_start) > (1 * HZ)) { |
|---|
| 891 | printk(MODULE_NAME ": Tx Dma status : %s\n", |
|---|
| 892 | ag7100_tx_stopped(mac) ? "inactive" : "active"); |
|---|
| 893 | #if 0 |
|---|
| 894 | printk(MODULE_NAME ": timestamp:%u jiffies:%u diff:%d\n",bp->trans_start,jiffies, |
|---|
| 895 | (jiffies - bp->trans_start)); |
|---|
| 896 | #endif |
|---|
| 897 | ag7100_dma_reset(mac); |
|---|
| 898 | return 1; |
|---|
| 899 | } |
|---|
| 900 | } |
|---|
| 901 | ag7100_ring_incr(tail); |
|---|
| 902 | } |
|---|
| 903 | return 0; |
|---|
| 904 | } |
|---|
| 905 | |
|---|
| 906 | |
|---|
| 907 | /* |
|---|
| 908 | * phy link state management |
|---|
| 909 | */ |
|---|
| 910 | static int |
|---|
| 911 | ag7100_check_link(ag7100_mac_t *mac) |
|---|
| 912 | { |
|---|
| 913 | struct net_device *dev = mac->mac_dev; |
|---|
| 914 | int carrier = netif_carrier_ok(dev), fdx, phy_up=1; |
|---|
| 915 | ag7100_phy_speed_t speed; |
|---|
| 916 | int rc; |
|---|
| 917 | |
|---|
| 918 | /* workaround for dma hang, seen on DIR-825 */ |
|---|
| 919 | if(check_for_dma_hang(mac)) |
|---|
| 920 | goto done; |
|---|
| 921 | |
|---|
| 922 | /* The vitesse switch uses an indirect method to communicate phy status |
|---|
| 923 | * so it is best to limit the number of calls to what is necessary. |
|---|
| 924 | * However a single call returns all three pieces of status information. |
|---|
| 925 | * |
|---|
| 926 | * This is a trivial change to the other PHYs ergo this change. |
|---|
| 927 | * |
|---|
| 928 | */ |
|---|
| 929 | |
|---|
| 930 | /* |
|---|
| 931 | ** If this is not connected, let's just jump out |
|---|
| 932 | */ |
|---|
| 933 | |
|---|
| 934 | if(mii_if(mac) > 3) |
|---|
| 935 | goto done; |
|---|
| 936 | |
|---|
| 937 | rc = ag7100_get_link_status(mac->mac_unit, &phy_up, &fdx, &speed); |
|---|
| 938 | if (rc < 0) |
|---|
| 939 | goto done; |
|---|
| 940 | |
|---|
| 941 | if (!phy_up) |
|---|
| 942 | { |
|---|
| 943 | if (carrier) |
|---|
| 944 | { |
|---|
| 945 | printk(MODULE_NAME ": unit %d: phy not up carrier %d\n", mac->mac_unit, carrier); |
|---|
| 946 | netif_carrier_off(dev); |
|---|
| 947 | } |
|---|
| 948 | goto done; |
|---|
| 949 | } |
|---|
| 950 | |
|---|
| 951 | /* |
|---|
| 952 | * phy is up. Either nothing changed or phy setttings changed while we |
|---|
| 953 | * were sleeping. |
|---|
| 954 | */ |
|---|
| 955 | |
|---|
| 956 | if ((fdx < 0) || (speed < 0)) |
|---|
| 957 | { |
|---|
| 958 | printk(MODULE_NAME ": phy not connected?\n"); |
|---|
| 959 | return 0; |
|---|
| 960 | } |
|---|
| 961 | |
|---|
| 962 | if (carrier && (speed == mac->mac_speed) && (fdx == mac->mac_fdx)) |
|---|
| 963 | goto done; |
|---|
| 964 | |
|---|
| 965 | printk(MODULE_NAME ": unit %d phy is up...", mac->mac_unit); |
|---|
| 966 | printk("%s %s %s\n", mii_str[mac->mac_unit][mii_if(mac)], |
|---|
| 967 | spd_str[speed], dup_str[fdx]); |
|---|
| 968 | |
|---|
| 969 | ag7100_set_mac_from_link(mac, speed, fdx); |
|---|
| 970 | |
|---|
| 971 | printk(MODULE_NAME ": done cfg2 %#x ifctl %#x miictrl %#x \n", |
|---|
| 972 | ag7100_reg_rd(mac, AG7100_MAC_CFG2), |
|---|
| 973 | ag7100_reg_rd(mac, AG7100_MAC_IFCTL), |
|---|
| 974 | ar7100_reg_rd(mii_reg(mac))); |
|---|
| 975 | /* |
|---|
| 976 | * in business |
|---|
| 977 | */ |
|---|
| 978 | netif_carrier_on(dev); |
|---|
| 979 | |
|---|
| 980 | done: |
|---|
| 981 | #if defined(CONFIG_ATHRS26_PHY) || defined(CONFIG_ATHRS16_PHY) |
|---|
| 982 | if(!phy_up) |
|---|
| 983 | mod_timer(&mac->mac_phy_timer, jiffies + AG7100_PHY_POLL_SECONDS*HZ/4); |
|---|
| 984 | else |
|---|
| 985 | #endif |
|---|
| 986 | mod_timer(&mac->mac_phy_timer, jiffies + AG7100_PHY_POLL_SECONDS*HZ); |
|---|
| 987 | |
|---|
| 988 | /* "Hydra WAN + RealTek PHY with a specific NetGear Hub" Rx hang workaround */ |
|---|
| 989 | #if 1//DMA mac hang |
|---|
| 990 | { |
|---|
| 991 | unsigned int perf_cnt = ag7100_get_rx_count(mac); |
|---|
| 992 | if (perf_cnt == 0xffffffff) { |
|---|
| 993 | /* we have saturated the counter. let it overflow to 0 */ |
|---|
| 994 | if (mac->mac_unit == 0) { |
|---|
| 995 | ar7100_reg_wr(AR7100_PERF0_COUNTER, 0); |
|---|
| 996 | } |
|---|
| 997 | else { |
|---|
| 998 | ar7100_reg_wr(AR7100_PERF1_COUNTER, 0); |
|---|
| 999 | } |
|---|
| 1000 | } |
|---|
| 1001 | int status; |
|---|
| 1002 | status = ag7100_reg_rd(mac, AG7100_DMA_RX_STATUS); |
|---|
| 1003 | /* perf_cnt increments on every rx pkt including runts. |
|---|
| 1004 | * so, the rx hang occurred when perf_cnt incremented, but |
|---|
| 1005 | * valid rx pkts didn't get incremented. this could result |
|---|
| 1006 | * in a false positive but the likelihood that over a 2sec |
|---|
| 1007 | * period all pkts received were runts appears to me |
|---|
| 1008 | * to be very low -JK. |
|---|
| 1009 | */ |
|---|
| 1010 | |
|---|
| 1011 | if ((perf_cnt > rx_hang_detect_pkt_cnt_all[mac->mac_unit]) && |
|---|
| 1012 | (mac->net_rx_packets == rx_hang_detect_pkt_cnt_valid[mac->mac_unit]) && |
|---|
| 1013 | (!(status & AG7100_RX_STATUS_PKT_RCVD)) && |
|---|
| 1014 | (!((status & AG7100_RX_STATUS_PKTCNT_MASK )>>16))) { |
|---|
| 1015 | rx_hang_detected[mac->mac_unit] += 1; |
|---|
| 1016 | if ( mac->mac_unit == 1 ) |
|---|
| 1017 | printk(MODULE_NAME ": WAN Rx Hang Detected %d times!\n",rx_hang_detected[mac->mac_unit]); |
|---|
| 1018 | else |
|---|
| 1019 | printk(MODULE_NAME ": LAN Rx Hang Detected %d times!\n",rx_hang_detected[mac->mac_unit]); |
|---|
| 1020 | rx_hang_detect_pkt_cnt_all[mac->mac_unit] = perf_cnt; |
|---|
| 1021 | rx_hang_detect_pkt_cnt_valid[mac->mac_unit] = mac->net_rx_packets; |
|---|
| 1022 | |
|---|
| 1023 | if (rx_hang_detected[mac->mac_unit] >= 2) |
|---|
| 1024 | ag7100_dma_reset(mac); |
|---|
| 1025 | } |
|---|
| 1026 | else { |
|---|
| 1027 | rx_hang_detect_pkt_cnt_all[mac->mac_unit] = perf_cnt; |
|---|
| 1028 | rx_hang_detect_pkt_cnt_valid[mac->mac_unit] = mac->net_rx_packets; |
|---|
| 1029 | rx_hang_detected[mac->mac_unit] = 0; |
|---|
| 1030 | } |
|---|
| 1031 | } |
|---|
| 1032 | #endif |
|---|
| 1033 | |
|---|
| 1034 | return 0; |
|---|
| 1035 | } |
|---|
| 1036 | |
|---|
| 1037 | static void |
|---|
| 1038 | ag7100_choose_phy(uint32_t phy_addr) |
|---|
| 1039 | { |
|---|
| 1040 | #ifdef CONFIG_AR7100_EMULATION |
|---|
| 1041 | if (phy_addr == 0x10) |
|---|
| 1042 | { |
|---|
| 1043 | ar7100_reg_rmw_set(AR7100_MII0_CTRL, (1 << 6)); |
|---|
| 1044 | } |
|---|
| 1045 | else |
|---|
| 1046 | { |
|---|
| 1047 | ar7100_reg_rmw_clear(AR7100_MII0_CTRL, (1 << 6)); |
|---|
| 1048 | } |
|---|
| 1049 | #endif |
|---|
| 1050 | } |
|---|
| 1051 | |
|---|
| 1052 | uint16_t |
|---|
| 1053 | ag7100_mii_read(int unit, uint32_t phy_addr, uint8_t reg) |
|---|
| 1054 | { |
|---|
| 1055 | ag7100_mac_t *mac = ag7100_unit2mac(0); |
|---|
| 1056 | uint16_t addr = (phy_addr << AG7100_ADDR_SHIFT) | reg, val; |
|---|
| 1057 | volatile int rddata; |
|---|
| 1058 | uint16_t ii = 0x1000; |
|---|
| 1059 | |
|---|
| 1060 | ag7100_choose_phy(phy_addr); |
|---|
| 1061 | |
|---|
| 1062 | ag7100_reg_wr(mac, AG7100_MII_MGMT_CMD, 0x0); |
|---|
| 1063 | ag7100_reg_wr(mac, AG7100_MII_MGMT_ADDRESS, addr); |
|---|
| 1064 | ag7100_reg_wr(mac, AG7100_MII_MGMT_CMD, AG7100_MGMT_CMD_READ); |
|---|
| 1065 | |
|---|
| 1066 | do |
|---|
| 1067 | { |
|---|
| 1068 | udelay(5); |
|---|
| 1069 | rddata = ag7100_reg_rd(mac, AG7100_MII_MGMT_IND) & 0x1; |
|---|
| 1070 | }while(rddata && --ii); |
|---|
| 1071 | |
|---|
| 1072 | val = ag7100_reg_rd(mac, AG7100_MII_MGMT_STATUS); |
|---|
| 1073 | ag7100_reg_wr(mac, AG7100_MII_MGMT_CMD, 0x0); |
|---|
| 1074 | |
|---|
| 1075 | return val; |
|---|
| 1076 | } |
|---|
| 1077 | |
|---|
| 1078 | void |
|---|
| 1079 | ag7100_mii_write(int unit, uint32_t phy_addr, uint8_t reg, uint16_t data) |
|---|
| 1080 | { |
|---|
| 1081 | ag7100_mac_t *mac = ag7100_unit2mac(0); |
|---|
| 1082 | uint16_t addr = (phy_addr << AG7100_ADDR_SHIFT) | reg; |
|---|
| 1083 | volatile int rddata; |
|---|
| 1084 | uint16_t ii = 0x1000; |
|---|
| 1085 | |
|---|
| 1086 | ag7100_choose_phy(phy_addr); |
|---|
| 1087 | |
|---|
| 1088 | ag7100_reg_wr(mac, AG7100_MII_MGMT_ADDRESS, addr); |
|---|
| 1089 | ag7100_reg_wr(mac, AG7100_MII_MGMT_CTRL, data); |
|---|
| 1090 | |
|---|
| 1091 | do |
|---|
| 1092 | { |
|---|
| 1093 | rddata = ag7100_reg_rd(mac, AG7100_MII_MGMT_IND) & 0x1; |
|---|
| 1094 | }while(rddata && --ii); |
|---|
| 1095 | } |
|---|
| 1096 | |
|---|
| 1097 | /* |
|---|
| 1098 | * Tx operation: |
|---|
| 1099 | * We do lazy reaping - only when the ring is "thresh" full. If the ring is |
|---|
| 1100 | * full and the hardware is not even done with the first pkt we q'd, we turn |
|---|
| 1101 | * on the tx interrupt, stop all q's and wait for h/w to |
|---|
| 1102 | * tell us when its done with a "few" pkts, and then turn the Qs on again. |
|---|
| 1103 | * |
|---|
| 1104 | * Locking: |
|---|
| 1105 | * The interrupt only touches the ring when Q's stopped => Tx is lockless, |
|---|
| 1106 | * except when handling ring full. |
|---|
| 1107 | * |
|---|
| 1108 | * Desc Flushing: Flushing needs to be handled at various levels, broadly: |
|---|
| 1109 | * - The DDr FIFOs for desc reads. |
|---|
| 1110 | * - WB's for desc writes. |
|---|
| 1111 | */ |
|---|
| 1112 | static void |
|---|
| 1113 | ag7100_handle_tx_full(ag7100_mac_t *mac) |
|---|
| 1114 | { |
|---|
| 1115 | u32 flags; |
|---|
| 1116 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 1117 | if(!mac->speed_10t) |
|---|
| 1118 | #endif |
|---|
| 1119 | assert(!netif_queue_stopped(mac->mac_dev)); |
|---|
| 1120 | |
|---|
| 1121 | mac->mac_net_stats.tx_fifo_errors ++; |
|---|
| 1122 | |
|---|
| 1123 | netif_stop_queue(mac->mac_dev); |
|---|
| 1124 | |
|---|
| 1125 | spin_lock_irqsave(&mac->mac_lock, flags); |
|---|
| 1126 | ag7100_intr_enable_tx(mac); |
|---|
| 1127 | spin_unlock_irqrestore(&mac->mac_lock, flags); |
|---|
| 1128 | } |
|---|
| 1129 | |
|---|
| 1130 | /* ****************************** |
|---|
| 1131 | * |
|---|
| 1132 | * Code under test - do not use |
|---|
| 1133 | * |
|---|
| 1134 | * ****************************** |
|---|
| 1135 | */ |
|---|
| 1136 | |
|---|
| 1137 | static ag7100_desc_t * |
|---|
| 1138 | ag7100_get_tx_ds(ag7100_mac_t *mac, int *len, unsigned char **start) |
|---|
| 1139 | { |
|---|
| 1140 | ag7100_desc_t *ds; |
|---|
| 1141 | int len_this_ds; |
|---|
| 1142 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 1143 | ag7100_buffer_t *bp; |
|---|
| 1144 | |
|---|
| 1145 | /* force extra pkt if remainder less than 4 bytes */ |
|---|
| 1146 | if (*len > tx_len_per_ds) |
|---|
| 1147 | if (*len <= (tx_len_per_ds + 4)) |
|---|
| 1148 | len_this_ds = tx_len_per_ds - 4; |
|---|
| 1149 | else |
|---|
| 1150 | len_this_ds = tx_len_per_ds; |
|---|
| 1151 | else |
|---|
| 1152 | len_this_ds = *len; |
|---|
| 1153 | |
|---|
| 1154 | ds = &r->ring_desc[r->ring_head]; |
|---|
| 1155 | |
|---|
| 1156 | ag7100_trc_new(ds,"ds addr"); |
|---|
| 1157 | ag7100_trc_new(ds,"ds len"); |
|---|
| 1158 | if(ag7100_tx_owned_by_dma(ds)) |
|---|
| 1159 | ag7100_dma_reset(mac); |
|---|
| 1160 | |
|---|
| 1161 | ds->pkt_size = len_this_ds; |
|---|
| 1162 | ds->pkt_start_addr = virt_to_phys(*start); |
|---|
| 1163 | ds->more = 1; |
|---|
| 1164 | |
|---|
| 1165 | *len -= len_this_ds; |
|---|
| 1166 | *start += len_this_ds; |
|---|
| 1167 | |
|---|
| 1168 | bp = &r->ring_buffer[r->ring_head]; |
|---|
| 1169 | bp->trans_start = jiffies; /*Time stamp each packet */ |
|---|
| 1170 | |
|---|
| 1171 | ag7100_ring_incr(r->ring_head); |
|---|
| 1172 | |
|---|
| 1173 | return ds; |
|---|
| 1174 | } |
|---|
| 1175 | |
|---|
| 1176 | #if defined(CONFIG_ATHRS26_PHY) |
|---|
| 1177 | int |
|---|
| 1178 | #else |
|---|
| 1179 | static int |
|---|
| 1180 | #endif |
|---|
| 1181 | ag7100_hard_start(struct sk_buff *skb, struct net_device *dev) |
|---|
| 1182 | { |
|---|
| 1183 | ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; |
|---|
| 1184 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 1185 | ag7100_buffer_t *bp; |
|---|
| 1186 | ag7100_desc_t *ds, *fds; |
|---|
| 1187 | unsigned char *start; |
|---|
| 1188 | int len; |
|---|
| 1189 | int nds_this_pkt; |
|---|
| 1190 | |
|---|
| 1191 | #ifdef VSC73XX_DEBUG |
|---|
| 1192 | { |
|---|
| 1193 | static int vsc73xx_dbg; |
|---|
| 1194 | if (vsc73xx_dbg == 0) { |
|---|
| 1195 | vsc73xx_get_link_status_dbg(); |
|---|
| 1196 | vsc73xx_dbg = 1; |
|---|
| 1197 | } |
|---|
| 1198 | vsc73xx_dbg = (vsc73xx_dbg + 1) % 10; |
|---|
| 1199 | } |
|---|
| 1200 | #endif |
|---|
| 1201 | |
|---|
| 1202 | #if defined(CONFIG_ATHRS26_PHY) && defined(HEADER_EN) |
|---|
| 1203 | /* add header to normal frames */ |
|---|
| 1204 | /* check if normal frames */ |
|---|
| 1205 | if ((mac->mac_unit == 0) && (!((skb->cb[0] == 0x7f) && (skb->cb[1] == 0x5d)))) |
|---|
| 1206 | { |
|---|
| 1207 | skb_push(skb, HEADER_LEN); |
|---|
| 1208 | skb->data[0] = 0x10; /* broadcast = 0; from_cpu = 0; reserved = 1; port_num = 0 */ |
|---|
| 1209 | skb->data[1] = 0x80; /* reserved = 0b10; priority = 0; type = 0 (normal) */ |
|---|
| 1210 | } |
|---|
| 1211 | |
|---|
| 1212 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
|---|
| 1213 | if(unlikely((skb->len <= 0) |
|---|
| 1214 | || (skb->len > (dev->mtu + ETH_HLEN + HEADER_LEN + 4)))) |
|---|
| 1215 | { /*vlan tag length = 4*/ |
|---|
| 1216 | printk(MODULE_NAME ": [%d] bad skb, dev->mtu=%d,ETH_HLEN=%d len %d\n", mac->mac_unit, dev->mtu, ETH_HLEN, skb->len); |
|---|
| 1217 | goto dropit; |
|---|
| 1218 | } |
|---|
| 1219 | #else |
|---|
| 1220 | if(unlikely((skb->len <= 0) |
|---|
| 1221 | || (skb->len > (dev->mtu + ETH_HLEN + HEADER_LEN)))) |
|---|
| 1222 | { |
|---|
| 1223 | printk(MODULE_NAME ": [%d] bad skb, dev->mtu=%d,ETH_HLEN=%d len %d\n", mac->mac_unit, dev->mtu, ETH_HLEN, skb->len); |
|---|
| 1224 | goto dropit; |
|---|
| 1225 | } |
|---|
| 1226 | #endif |
|---|
| 1227 | |
|---|
| 1228 | #else |
|---|
| 1229 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
|---|
| 1230 | if(unlikely((skb->len <= 0) || (skb->len > (dev->mtu + ETH_HLEN + 4)))) |
|---|
| 1231 | { /*vlan tag length = 4*/ |
|---|
| 1232 | printk(MODULE_NAME ": bad skb, len %d\n", skb->len); |
|---|
| 1233 | goto dropit; |
|---|
| 1234 | } |
|---|
| 1235 | #else |
|---|
| 1236 | if(unlikely((skb->len <= 0) || (skb->len > (dev->mtu + ETH_HLEN)))) |
|---|
| 1237 | { |
|---|
| 1238 | printk(MODULE_NAME ": bad skb, len %d\n", skb->len); |
|---|
| 1239 | goto dropit; |
|---|
| 1240 | } |
|---|
| 1241 | #endif |
|---|
| 1242 | #endif |
|---|
| 1243 | |
|---|
| 1244 | if (ag7100_tx_reap_thresh(mac)) |
|---|
| 1245 | ag7100_tx_reap(mac); |
|---|
| 1246 | |
|---|
| 1247 | ag7100_trc_new(r->ring_head,"hard-stop hd"); |
|---|
| 1248 | ag7100_trc_new(r->ring_tail,"hard-stop tl"); |
|---|
| 1249 | |
|---|
| 1250 | ag7100_trc_new(skb->len, "len this pkt"); |
|---|
| 1251 | ag7100_trc_new(skb->data, "ptr 2 pkt"); |
|---|
| 1252 | |
|---|
| 1253 | dma_cache_wback((unsigned long)skb->data, skb->len); |
|---|
| 1254 | |
|---|
| 1255 | bp = &r->ring_buffer[r->ring_head]; |
|---|
| 1256 | bp->buf_pkt = skb; |
|---|
| 1257 | len = skb->len; |
|---|
| 1258 | start = skb->data; |
|---|
| 1259 | |
|---|
| 1260 | assert(len>4); |
|---|
| 1261 | |
|---|
| 1262 | nds_this_pkt = 1; |
|---|
| 1263 | fds = ds = ag7100_get_tx_ds(mac, &len, &start); |
|---|
| 1264 | |
|---|
| 1265 | while (len>0) |
|---|
| 1266 | { |
|---|
| 1267 | ds = ag7100_get_tx_ds(mac, &len, &start); |
|---|
| 1268 | nds_this_pkt++; |
|---|
| 1269 | ag7100_tx_give_to_dma(ds); |
|---|
| 1270 | } |
|---|
| 1271 | |
|---|
| 1272 | ds->more = 0; |
|---|
| 1273 | ag7100_tx_give_to_dma(fds); |
|---|
| 1274 | |
|---|
| 1275 | bp->buf_lastds = ds; |
|---|
| 1276 | bp->buf_nds = nds_this_pkt; |
|---|
| 1277 | |
|---|
| 1278 | ag7100_trc_new(ds,"last ds"); |
|---|
| 1279 | ag7100_trc_new(nds_this_pkt,"nmbr ds for this pkt"); |
|---|
| 1280 | |
|---|
| 1281 | wmb(); |
|---|
| 1282 | |
|---|
| 1283 | mac->net_tx_packets ++; |
|---|
| 1284 | mac->net_tx_bytes += skb->len; |
|---|
| 1285 | |
|---|
| 1286 | ag7100_trc(ag7100_reg_rd(mac, AG7100_DMA_TX_CTRL),"dma idle"); |
|---|
| 1287 | |
|---|
| 1288 | ag7100_tx_start(mac); |
|---|
| 1289 | |
|---|
| 1290 | if (unlikely(ag7100_tx_ring_full(mac))) |
|---|
| 1291 | ag7100_handle_tx_full(mac); |
|---|
| 1292 | |
|---|
| 1293 | dev->trans_start = jiffies; |
|---|
| 1294 | |
|---|
| 1295 | return NETDEV_TX_OK; |
|---|
| 1296 | |
|---|
| 1297 | dropit: |
|---|
| 1298 | printk(MODULE_NAME ": dropping skb %p\n", skb); |
|---|
| 1299 | kfree_skb(skb); |
|---|
| 1300 | return NETDEV_TX_OK; |
|---|
| 1301 | } |
|---|
| 1302 | |
|---|
| 1303 | /* |
|---|
| 1304 | * Interrupt handling: |
|---|
| 1305 | * - Recv NAPI style (refer to Documentation/networking/NAPI) |
|---|
| 1306 | * |
|---|
| 1307 | * 2 Rx interrupts: RX and Overflow (OVF). |
|---|
| 1308 | * - If we get RX and/or OVF, schedule a poll. Turn off _both_ interurpts. |
|---|
| 1309 | * |
|---|
| 1310 | * - When our poll's called, we |
|---|
| 1311 | * a) Have one or more packets to process and replenish |
|---|
| 1312 | * b) The hardware may have stopped because of an OVF. |
|---|
| 1313 | * |
|---|
| 1314 | * - We process and replenish as much as we can. For every rcvd pkt |
|---|
| 1315 | * indicated up the stack, the head moves. For every such slot that we |
|---|
| 1316 | * replenish with an skb, the tail moves. If head catches up with the tail |
|---|
| 1317 | * we're OOM. When all's done, we consider where we're at: |
|---|
| 1318 | * |
|---|
| 1319 | * if no OOM: |
|---|
| 1320 | * - if we're out of quota, let the ints be disabled and poll scheduled. |
|---|
| 1321 | * - If we've processed everything, enable ints and cancel poll. |
|---|
| 1322 | * |
|---|
| 1323 | * If OOM: |
|---|
| 1324 | * - Start a timer. Cancel poll. Ints still disabled. |
|---|
| 1325 | * If the hardware's stopped, no point in restarting yet. |
|---|
| 1326 | * |
|---|
| 1327 | * Note that in general, whether we're OOM or not, we still try to |
|---|
| 1328 | * indicate everything recvd, up. |
|---|
| 1329 | * |
|---|
| 1330 | * Locking: |
|---|
| 1331 | * The interrupt doesnt touch the ring => Rx is lockless |
|---|
| 1332 | * |
|---|
| 1333 | */ |
|---|
| 1334 | static irqreturn_t |
|---|
| 1335 | ag7100_intr(int cpl, void *dev_id) |
|---|
| 1336 | { |
|---|
| 1337 | struct net_device *dev = (struct net_device *)dev_id; |
|---|
| 1338 | ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; |
|---|
| 1339 | int isr, imr, handled = 0; |
|---|
| 1340 | |
|---|
| 1341 | isr = ag7100_get_isr(mac); |
|---|
| 1342 | imr = ag7100_reg_rd(mac, AG7100_DMA_INTR_MASK); |
|---|
| 1343 | |
|---|
| 1344 | ag7100_trc(isr,"isr"); |
|---|
| 1345 | ag7100_trc(imr,"imr"); |
|---|
| 1346 | |
|---|
| 1347 | assert(isr == (isr & imr)); |
|---|
| 1348 | |
|---|
| 1349 | if (likely(isr & (AG7100_INTR_RX | AG7100_INTR_RX_OVF))) |
|---|
| 1350 | { |
|---|
| 1351 | handled = 1; |
|---|
| 1352 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 1353 | if (likely(netif_rx_schedule_prep(dev,&mac->mac_napi))) |
|---|
| 1354 | #else |
|---|
| 1355 | if (likely(netif_rx_schedule_prep(dev))) |
|---|
| 1356 | #endif |
|---|
| 1357 | { |
|---|
| 1358 | ag7100_intr_disable_recv(mac); |
|---|
| 1359 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 1360 | __netif_rx_schedule(dev,&mac->mac_napi); |
|---|
| 1361 | #else |
|---|
| 1362 | __netif_rx_schedule(dev); |
|---|
| 1363 | #endif |
|---|
| 1364 | } |
|---|
| 1365 | else |
|---|
| 1366 | { |
|---|
| 1367 | printk(MODULE_NAME ": driver bug! interrupt while in poll\n"); |
|---|
| 1368 | assert(0); |
|---|
| 1369 | ag7100_intr_disable_recv(mac); |
|---|
| 1370 | } |
|---|
| 1371 | /*ag7100_recv_packets(dev, mac, 200, &budget);*/ |
|---|
| 1372 | } |
|---|
| 1373 | if (likely(isr & AG7100_INTR_TX)) |
|---|
| 1374 | { |
|---|
| 1375 | handled = 1; |
|---|
| 1376 | ag7100_intr_ack_tx(mac); |
|---|
| 1377 | ag7100_tx_reap(mac); |
|---|
| 1378 | } |
|---|
| 1379 | if (unlikely(isr & AG7100_INTR_RX_BUS_ERROR)) |
|---|
| 1380 | { |
|---|
| 1381 | assert(0); |
|---|
| 1382 | handled = 1; |
|---|
| 1383 | ag7100_intr_ack_rxbe(mac); |
|---|
| 1384 | } |
|---|
| 1385 | if (unlikely(isr & AG7100_INTR_TX_BUS_ERROR)) |
|---|
| 1386 | { |
|---|
| 1387 | assert(0); |
|---|
| 1388 | handled = 1; |
|---|
| 1389 | ag7100_intr_ack_txbe(mac); |
|---|
| 1390 | } |
|---|
| 1391 | |
|---|
| 1392 | if (!handled) |
|---|
| 1393 | { |
|---|
| 1394 | assert(0); |
|---|
| 1395 | printk(MODULE_NAME ": unhandled intr isr %#x\n", isr); |
|---|
| 1396 | } |
|---|
| 1397 | |
|---|
| 1398 | return IRQ_HANDLED; |
|---|
| 1399 | } |
|---|
| 1400 | |
|---|
| 1401 | /* |
|---|
| 1402 | * Rx and Tx DMA hangs and goes to an invalid state in HOWL boards |
|---|
| 1403 | * when the link partner is forced to 10/100 Mode.By resetting the MAC |
|---|
| 1404 | * we are able to recover from this state.This is a software WAR and |
|---|
| 1405 | * will be removed once we have a hardware fix. |
|---|
| 1406 | */ |
|---|
| 1407 | |
|---|
| 1408 | #if 1//def CONFIG_AR9100 |
|---|
| 1409 | |
|---|
| 1410 | void ag7100_dma_reset(ag7100_mac_t *mac) |
|---|
| 1411 | { |
|---|
| 1412 | uint32_t mask; |
|---|
| 1413 | |
|---|
| 1414 | if(mac->mac_unit) |
|---|
| 1415 | mask = AR7100_RESET_GE1_MAC; |
|---|
| 1416 | else |
|---|
| 1417 | mask = AR7100_RESET_GE0_MAC; |
|---|
| 1418 | |
|---|
| 1419 | ar7100_reg_rmw_set(AR7100_RESET, mask); |
|---|
| 1420 | mdelay(100); |
|---|
| 1421 | ar7100_reg_rmw_clear(AR7100_RESET, mask); |
|---|
| 1422 | mdelay(100); |
|---|
| 1423 | |
|---|
| 1424 | ag7100_intr_disable_recv(mac); |
|---|
| 1425 | #if defined(CONFIG_AR9100) && defined(CONFIG_AG7100_GE1_RMII) |
|---|
| 1426 | mac->speed_10t = 0; |
|---|
| 1427 | #endif |
|---|
| 1428 | schedule_work(&mac->mac_tx_timeout); |
|---|
| 1429 | } |
|---|
| 1430 | |
|---|
| 1431 | #endif |
|---|
| 1432 | |
|---|
| 1433 | static int |
|---|
| 1434 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 1435 | ag7100_poll(struct napi_struct *napi, int budget) |
|---|
| 1436 | #else |
|---|
| 1437 | ag7100_poll(struct net_device *dev, int *budget) |
|---|
| 1438 | #endif |
|---|
| 1439 | { |
|---|
| 1440 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 1441 | ag7100_mac_t *mac = container_of(napi, ag7100_mac_t, mac_napi); |
|---|
| 1442 | struct net_device *dev = mac->mac_dev; |
|---|
| 1443 | int work_done, max_work = budget, status = 0; |
|---|
| 1444 | #else |
|---|
| 1445 | ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; |
|---|
| 1446 | int work_done, max_work = min(*budget, dev->quota), status = 0; |
|---|
| 1447 | #endif |
|---|
| 1448 | ag7100_rx_status_t ret; |
|---|
| 1449 | u32 flags; |
|---|
| 1450 | spin_lock_irqsave(&mac->mac_lock, flags); |
|---|
| 1451 | |
|---|
| 1452 | ret = ag7100_recv_packets(dev, mac, max_work, &work_done); |
|---|
| 1453 | |
|---|
| 1454 | |
|---|
| 1455 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 1456 | if (work_done < budget) |
|---|
| 1457 | { |
|---|
| 1458 | netif_rx_complete(dev, napi); |
|---|
| 1459 | ag7100_intr_enable_recv(mac); |
|---|
| 1460 | } |
|---|
| 1461 | #else |
|---|
| 1462 | dev->quota -= work_done; |
|---|
| 1463 | *budget -= work_done; |
|---|
| 1464 | if (likely(ret == AG7100_RX_STATUS_DONE)) |
|---|
| 1465 | { |
|---|
| 1466 | netif_rx_complete(dev); |
|---|
| 1467 | } |
|---|
| 1468 | #endif |
|---|
| 1469 | if(ret == AG7100_RX_DMA_HANG) |
|---|
| 1470 | { |
|---|
| 1471 | status = 0; |
|---|
| 1472 | ag7100_dma_reset(mac); |
|---|
| 1473 | } |
|---|
| 1474 | |
|---|
| 1475 | if (likely(ret == AG7100_RX_STATUS_NOT_DONE)) |
|---|
| 1476 | { |
|---|
| 1477 | /* |
|---|
| 1478 | * We have work left |
|---|
| 1479 | */ |
|---|
| 1480 | status = 1; |
|---|
| 1481 | } |
|---|
| 1482 | else if (ret == AG7100_RX_STATUS_OOM) |
|---|
| 1483 | { |
|---|
| 1484 | printk(MODULE_NAME ": oom..?\n"); |
|---|
| 1485 | /* |
|---|
| 1486 | * Start timer, stop polling, but do not enable rx interrupts. |
|---|
| 1487 | */ |
|---|
| 1488 | mod_timer(&mac->mac_oom_timer, jiffies+1); |
|---|
| 1489 | } |
|---|
| 1490 | spin_unlock_irqrestore(&mac->mac_lock, flags); |
|---|
| 1491 | |
|---|
| 1492 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 1493 | return work_done; |
|---|
| 1494 | #else |
|---|
| 1495 | return status; |
|---|
| 1496 | #endif |
|---|
| 1497 | } |
|---|
| 1498 | |
|---|
| 1499 | int |
|---|
| 1500 | ag7100_recv_packets(struct net_device *dev, ag7100_mac_t *mac, |
|---|
| 1501 | int quota, int *work_done) |
|---|
| 1502 | { |
|---|
| 1503 | ag7100_ring_t *r = &mac->mac_rxring; |
|---|
| 1504 | ag7100_desc_t *ds; |
|---|
| 1505 | ag7100_buffer_t *bp; |
|---|
| 1506 | struct sk_buff *skb; |
|---|
| 1507 | ag7100_rx_status_t ret = AG7100_RX_STATUS_DONE; |
|---|
| 1508 | int head = r->ring_head, len, status, iquota = quota, more_pkts, rep; |
|---|
| 1509 | int i; |
|---|
| 1510 | ag7100_trc(iquota,"iquota"); |
|---|
| 1511 | #if !defined(CONFIG_AR9100) |
|---|
| 1512 | status = ag7100_reg_rd(mac, AG7100_DMA_RX_STATUS); |
|---|
| 1513 | #endif |
|---|
| 1514 | |
|---|
| 1515 | process_pkts: |
|---|
| 1516 | ag7100_trc(status,"status"); |
|---|
| 1517 | #if !defined(CONFIG_AR9100) |
|---|
| 1518 | /* |
|---|
| 1519 | * Under stress, the following assertion fails. |
|---|
| 1520 | * |
|---|
| 1521 | * On investigation, the following `appears' to happen. |
|---|
| 1522 | * - pkts received |
|---|
| 1523 | * - rx intr |
|---|
| 1524 | * - poll invoked |
|---|
| 1525 | * - process received pkts |
|---|
| 1526 | * - replenish buffers |
|---|
| 1527 | * - pkts received |
|---|
| 1528 | * |
|---|
| 1529 | * - NO RX INTR & STATUS REG NOT UPDATED <--- |
|---|
| 1530 | * |
|---|
| 1531 | * - s/w doesn't process pkts since no intr |
|---|
| 1532 | * - eventually, no more buffers for h/w to put |
|---|
| 1533 | * future rx pkts |
|---|
| 1534 | * - RX overflow intr |
|---|
| 1535 | * - poll invoked |
|---|
| 1536 | * - since status reg is not getting updated |
|---|
| 1537 | * following assertion fails.. |
|---|
| 1538 | * |
|---|
| 1539 | * Ignore the status register. Regardless of this |
|---|
| 1540 | * being a rx or rx overflow, we have packets to process. |
|---|
| 1541 | * So, we go ahead and receive the packets.. |
|---|
| 1542 | */ |
|---|
| 1543 | assert((status & AG7100_RX_STATUS_PKT_RCVD)); |
|---|
| 1544 | assert((status >> 16)); |
|---|
| 1545 | #endif |
|---|
| 1546 | /* |
|---|
| 1547 | * Flush the DDR FIFOs for our gmac |
|---|
| 1548 | */ |
|---|
| 1549 | ar7100_flush_ge(mac->mac_unit); |
|---|
| 1550 | |
|---|
| 1551 | assert(quota > 0); /* WCL */ |
|---|
| 1552 | |
|---|
| 1553 | while(quota) |
|---|
| 1554 | { |
|---|
| 1555 | ds = &r->ring_desc[head]; |
|---|
| 1556 | |
|---|
| 1557 | ag7100_trc(head,"hd"); |
|---|
| 1558 | ag7100_trc(ds, "ds"); |
|---|
| 1559 | |
|---|
| 1560 | if (ag7100_rx_owned_by_dma(ds)) |
|---|
| 1561 | { |
|---|
| 1562 | if(quota == iquota) |
|---|
| 1563 | { |
|---|
| 1564 | *work_done = quota = 0; |
|---|
| 1565 | return AG7100_RX_DMA_HANG; |
|---|
| 1566 | } |
|---|
| 1567 | break; |
|---|
| 1568 | } |
|---|
| 1569 | ag7100_intr_ack_rx(mac); |
|---|
| 1570 | |
|---|
| 1571 | bp = &r->ring_buffer[head]; |
|---|
| 1572 | len = ds->pkt_size; |
|---|
| 1573 | skb = bp->buf_pkt; |
|---|
| 1574 | assert(skb); |
|---|
| 1575 | skb_put(skb, len - ETHERNET_FCS_SIZE); |
|---|
| 1576 | |
|---|
| 1577 | #if defined(CONFIG_ATHRS26_PHY) && defined(HEADER_EN) |
|---|
| 1578 | uint8_t type; |
|---|
| 1579 | uint16_t def_vid; |
|---|
| 1580 | |
|---|
| 1581 | if(mac->mac_unit == 0) |
|---|
| 1582 | { |
|---|
| 1583 | type = (skb->data[1]) & 0xf; |
|---|
| 1584 | |
|---|
| 1585 | if (type == NORMAL_PACKET) |
|---|
| 1586 | { |
|---|
| 1587 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
|---|
| 1588 | /*cpu egress tagged*/ |
|---|
| 1589 | if (is_cpu_egress_tagged()) |
|---|
| 1590 | { |
|---|
| 1591 | if ((skb->data[12 + HEADER_LEN] != 0x81) || (skb->data[13 + HEADER_LEN] != 0x00)) |
|---|
| 1592 | { |
|---|
| 1593 | def_vid = athrs26_defvid_get(skb->data[0] & 0xf); |
|---|
| 1594 | skb_push(skb, 2); /* vid lenghth - header length */ |
|---|
| 1595 | memmove(&skb->data[0], &skb->data[4], 12); /*remove header and add vlan tag*/ |
|---|
| 1596 | |
|---|
| 1597 | skb->data[12] = 0x81; |
|---|
| 1598 | skb->data[13] = 0x00; |
|---|
| 1599 | skb->data[14] = (def_vid >> 8) & 0xf; |
|---|
| 1600 | skb->data[15] = def_vid & 0xff; |
|---|
| 1601 | } |
|---|
| 1602 | } |
|---|
| 1603 | else |
|---|
| 1604 | #endif |
|---|
| 1605 | skb_pull(skb, 2); /* remove attansic header */ |
|---|
| 1606 | |
|---|
| 1607 | mac->net_rx_packets ++; |
|---|
| 1608 | mac->net_rx_bytes += skb->len; |
|---|
| 1609 | #if 0//def CONFIG_CAMEO_REALTEK_PHY |
|---|
| 1610 | /* align the data to the ip header - should be faster than copying the entire packet */ |
|---|
| 1611 | for (i = len - (len % 4); i >= 0; i -= 4) { |
|---|
| 1612 | put_unaligned(*((u32 *) (skb->data + i)), (u32 *) (skb->data + i + 2)); |
|---|
| 1613 | } |
|---|
| 1614 | skb->data += 2; |
|---|
| 1615 | skb->tail += 2; |
|---|
| 1616 | #endif |
|---|
| 1617 | |
|---|
| 1618 | /* |
|---|
| 1619 | * also pulls the ether header |
|---|
| 1620 | */ |
|---|
| 1621 | skb->protocol = eth_type_trans(skb, dev); |
|---|
| 1622 | skb->dev = dev; |
|---|
| 1623 | bp->buf_pkt = NULL; |
|---|
| 1624 | dev->last_rx = jiffies; |
|---|
| 1625 | quota--; |
|---|
| 1626 | |
|---|
| 1627 | netif_receive_skb(skb); |
|---|
| 1628 | } |
|---|
| 1629 | else |
|---|
| 1630 | { |
|---|
| 1631 | mac->net_rx_packets ++; |
|---|
| 1632 | mac->net_rx_bytes += skb->len; |
|---|
| 1633 | bp->buf_pkt = NULL; |
|---|
| 1634 | dev->last_rx = jiffies; |
|---|
| 1635 | quota--; |
|---|
| 1636 | |
|---|
| 1637 | if (type == READ_WRITE_REG_ACK) |
|---|
| 1638 | { |
|---|
| 1639 | header_receive_skb(skb); |
|---|
| 1640 | } |
|---|
| 1641 | else |
|---|
| 1642 | { |
|---|
| 1643 | kfree_skb(skb); |
|---|
| 1644 | } |
|---|
| 1645 | } |
|---|
| 1646 | }else |
|---|
| 1647 | { |
|---|
| 1648 | mac->net_rx_packets ++; |
|---|
| 1649 | mac->net_rx_bytes += skb->len; |
|---|
| 1650 | /* |
|---|
| 1651 | * also pulls the ether header |
|---|
| 1652 | */ |
|---|
| 1653 | skb->protocol = eth_type_trans(skb, dev); |
|---|
| 1654 | skb->dev = dev; |
|---|
| 1655 | bp->buf_pkt = NULL; |
|---|
| 1656 | dev->last_rx = jiffies; |
|---|
| 1657 | quota--; |
|---|
| 1658 | |
|---|
| 1659 | netif_receive_skb(skb); |
|---|
| 1660 | } |
|---|
| 1661 | |
|---|
| 1662 | #else |
|---|
| 1663 | mac->net_rx_packets ++; |
|---|
| 1664 | mac->net_rx_bytes += skb->len; |
|---|
| 1665 | /* |
|---|
| 1666 | * also pulls the ether header |
|---|
| 1667 | */ |
|---|
| 1668 | skb->protocol = eth_type_trans(skb, dev); |
|---|
| 1669 | skb->dev = dev; |
|---|
| 1670 | bp->buf_pkt = NULL; |
|---|
| 1671 | dev->last_rx = jiffies; |
|---|
| 1672 | |
|---|
| 1673 | quota--; |
|---|
| 1674 | |
|---|
| 1675 | netif_receive_skb(skb); |
|---|
| 1676 | #endif |
|---|
| 1677 | |
|---|
| 1678 | ag7100_ring_incr(head); |
|---|
| 1679 | } |
|---|
| 1680 | |
|---|
| 1681 | if(quota == iquota) |
|---|
| 1682 | { |
|---|
| 1683 | *work_done = quota = 0; |
|---|
| 1684 | return AG7100_RX_DMA_HANG; |
|---|
| 1685 | } |
|---|
| 1686 | |
|---|
| 1687 | r->ring_head = head; |
|---|
| 1688 | |
|---|
| 1689 | rep = ag7100_rx_replenish(mac); |
|---|
| 1690 | if(rep < 0) |
|---|
| 1691 | { |
|---|
| 1692 | *work_done =0 ; |
|---|
| 1693 | return AG7100_RX_DMA_HANG; |
|---|
| 1694 | } |
|---|
| 1695 | /* |
|---|
| 1696 | * let's see what changed while we were slogging. |
|---|
| 1697 | * ack Rx in the loop above is no flush version. It will get flushed now. |
|---|
| 1698 | */ |
|---|
| 1699 | status = ag7100_reg_rd(mac, AG7100_DMA_RX_STATUS); |
|---|
| 1700 | more_pkts = (status & AG7100_RX_STATUS_PKT_RCVD); |
|---|
| 1701 | |
|---|
| 1702 | ag7100_trc(more_pkts,"more_pkts"); |
|---|
| 1703 | |
|---|
| 1704 | if (!more_pkts) goto done; |
|---|
| 1705 | /* |
|---|
| 1706 | * more pkts arrived; if we have quota left, get rolling again |
|---|
| 1707 | */ |
|---|
| 1708 | if (quota) goto process_pkts; |
|---|
| 1709 | /* |
|---|
| 1710 | * out of quota |
|---|
| 1711 | */ |
|---|
| 1712 | ret = AG7100_RX_STATUS_NOT_DONE; |
|---|
| 1713 | |
|---|
| 1714 | done: |
|---|
| 1715 | *work_done = (iquota - quota); |
|---|
| 1716 | |
|---|
| 1717 | if (unlikely(ag7100_rx_ring_full(mac))) |
|---|
| 1718 | return AG7100_RX_STATUS_OOM; |
|---|
| 1719 | /* |
|---|
| 1720 | * !oom; if stopped, restart h/w |
|---|
| 1721 | */ |
|---|
| 1722 | |
|---|
| 1723 | if (unlikely(status & AG7100_RX_STATUS_OVF)) |
|---|
| 1724 | { |
|---|
| 1725 | mac->net_rx_over_errors ++; |
|---|
| 1726 | ag7100_intr_ack_rxovf(mac); |
|---|
| 1727 | ag7100_rx_start(mac); |
|---|
| 1728 | } |
|---|
| 1729 | |
|---|
| 1730 | return ret; |
|---|
| 1731 | } |
|---|
| 1732 | |
|---|
| 1733 | static struct sk_buff * |
|---|
| 1734 | ag7100_buffer_alloc(void) |
|---|
| 1735 | { |
|---|
| 1736 | struct sk_buff *skb; |
|---|
| 1737 | |
|---|
| 1738 | #if 0//def CONFIG_CAMEO_REALTEK_PHY |
|---|
| 1739 | skb = dev_alloc_skb(AG7100_RX_BUF_SIZE+4); |
|---|
| 1740 | #else |
|---|
| 1741 | skb = dev_alloc_skb(AG7100_RX_BUF_SIZE + AG7100_RX_RESERVE); |
|---|
| 1742 | #endif |
|---|
| 1743 | if (unlikely(!skb)) |
|---|
| 1744 | return NULL; |
|---|
| 1745 | skb_reserve(skb, AG7100_RX_RESERVE); |
|---|
| 1746 | |
|---|
| 1747 | return skb; |
|---|
| 1748 | } |
|---|
| 1749 | |
|---|
| 1750 | static void |
|---|
| 1751 | ag7100_buffer_free(struct sk_buff *skb) |
|---|
| 1752 | { |
|---|
| 1753 | if (in_irq()) |
|---|
| 1754 | dev_kfree_skb_irq(skb); |
|---|
| 1755 | else |
|---|
| 1756 | dev_kfree_skb(skb); |
|---|
| 1757 | } |
|---|
| 1758 | |
|---|
| 1759 | /* |
|---|
| 1760 | * Head is the first slot with a valid buffer. Tail is the last slot |
|---|
| 1761 | * replenished. Tries to refill buffers from tail to head. |
|---|
| 1762 | */ |
|---|
| 1763 | static int |
|---|
| 1764 | ag7100_rx_replenish(ag7100_mac_t *mac) |
|---|
| 1765 | { |
|---|
| 1766 | ag7100_ring_t *r = &mac->mac_rxring; |
|---|
| 1767 | int head = r->ring_head, tail = r->ring_tail, refilled = 0; |
|---|
| 1768 | ag7100_desc_t *ds; |
|---|
| 1769 | ag7100_buffer_t *bf; |
|---|
| 1770 | |
|---|
| 1771 | ag7100_trc(head,"hd"); |
|---|
| 1772 | ag7100_trc(tail,"tl"); |
|---|
| 1773 | |
|---|
| 1774 | do |
|---|
| 1775 | { |
|---|
| 1776 | bf = &r->ring_buffer[tail]; |
|---|
| 1777 | ds = &r->ring_desc[tail]; |
|---|
| 1778 | |
|---|
| 1779 | ag7100_trc(ds,"ds"); |
|---|
| 1780 | |
|---|
| 1781 | if(ag7100_rx_owned_by_dma(ds)) |
|---|
| 1782 | { |
|---|
| 1783 | return -1; |
|---|
| 1784 | } |
|---|
| 1785 | assert(!bf->buf_pkt); |
|---|
| 1786 | |
|---|
| 1787 | bf->buf_pkt = ag7100_buffer_alloc(); |
|---|
| 1788 | if (!bf->buf_pkt) |
|---|
| 1789 | { |
|---|
| 1790 | printk(MODULE_NAME ": outta skbs!\n"); |
|---|
| 1791 | break; |
|---|
| 1792 | } |
|---|
| 1793 | dma_cache_inv((unsigned long)bf->buf_pkt->data, AG7100_RX_BUF_SIZE); |
|---|
| 1794 | ds->pkt_start_addr = virt_to_phys(bf->buf_pkt->data); |
|---|
| 1795 | |
|---|
| 1796 | ag7100_rx_give_to_dma(ds); |
|---|
| 1797 | refilled ++; |
|---|
| 1798 | |
|---|
| 1799 | ag7100_ring_incr(tail); |
|---|
| 1800 | |
|---|
| 1801 | } while(tail != head); |
|---|
| 1802 | /* |
|---|
| 1803 | * Flush descriptors |
|---|
| 1804 | */ |
|---|
| 1805 | wmb(); |
|---|
| 1806 | |
|---|
| 1807 | r->ring_tail = tail; |
|---|
| 1808 | ag7100_trc(refilled,"refilled"); |
|---|
| 1809 | |
|---|
| 1810 | return refilled; |
|---|
| 1811 | } |
|---|
| 1812 | |
|---|
| 1813 | /* |
|---|
| 1814 | * Reap from tail till the head or whenever we encounter an unxmited packet. |
|---|
| 1815 | */ |
|---|
| 1816 | static int |
|---|
| 1817 | ag7100_tx_reap(ag7100_mac_t *mac) |
|---|
| 1818 | { |
|---|
| 1819 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 1820 | int head = r->ring_head, tail = r->ring_tail, reaped = 0, i; |
|---|
| 1821 | ag7100_desc_t *ds; |
|---|
| 1822 | ag7100_buffer_t *bf; |
|---|
| 1823 | uint32_t flags; |
|---|
| 1824 | |
|---|
| 1825 | ag7100_trc_new(head,"hd"); |
|---|
| 1826 | ag7100_trc_new(tail,"tl"); |
|---|
| 1827 | |
|---|
| 1828 | ar7100_flush_ge(mac->mac_unit); |
|---|
| 1829 | spin_lock_irqsave(&mac->mac_lock, flags); |
|---|
| 1830 | while(tail != head) |
|---|
| 1831 | { |
|---|
| 1832 | ds = &r->ring_desc[tail]; |
|---|
| 1833 | |
|---|
| 1834 | ag7100_trc_new(ds,"ds"); |
|---|
| 1835 | |
|---|
| 1836 | if(ag7100_tx_owned_by_dma(ds)) |
|---|
| 1837 | break; |
|---|
| 1838 | |
|---|
| 1839 | bf = &r->ring_buffer[tail]; |
|---|
| 1840 | assert(bf->buf_pkt); |
|---|
| 1841 | |
|---|
| 1842 | ag7100_trc_new(bf->buf_lastds,"lastds"); |
|---|
| 1843 | |
|---|
| 1844 | if(ag7100_tx_owned_by_dma(bf->buf_lastds)) |
|---|
| 1845 | break; |
|---|
| 1846 | |
|---|
| 1847 | for(i = 0; i < bf->buf_nds; i++) |
|---|
| 1848 | { |
|---|
| 1849 | ag7100_intr_ack_tx(mac); |
|---|
| 1850 | ag7100_ring_incr(tail); |
|---|
| 1851 | } |
|---|
| 1852 | |
|---|
| 1853 | ag7100_buffer_free(bf->buf_pkt); |
|---|
| 1854 | bf->buf_pkt = NULL; |
|---|
| 1855 | |
|---|
| 1856 | reaped ++; |
|---|
| 1857 | } |
|---|
| 1858 | spin_unlock_irqrestore(&mac->mac_lock, flags); |
|---|
| 1859 | |
|---|
| 1860 | r->ring_tail = tail; |
|---|
| 1861 | |
|---|
| 1862 | if (netif_queue_stopped(mac->mac_dev) && |
|---|
| 1863 | (ag7100_ndesc_unused(mac, r) >= AG7100_TX_QSTART_THRESH) && |
|---|
| 1864 | netif_carrier_ok(mac->mac_dev)) |
|---|
| 1865 | { |
|---|
| 1866 | if (ag7100_reg_rd(mac, AG7100_DMA_INTR_MASK) & AG7100_INTR_TX) |
|---|
| 1867 | { |
|---|
| 1868 | spin_lock_irqsave(&mac->mac_lock, flags); |
|---|
| 1869 | ag7100_intr_disable_tx(mac); |
|---|
| 1870 | spin_unlock_irqrestore(&mac->mac_lock, flags); |
|---|
| 1871 | } |
|---|
| 1872 | netif_wake_queue(mac->mac_dev); |
|---|
| 1873 | } |
|---|
| 1874 | |
|---|
| 1875 | return reaped; |
|---|
| 1876 | } |
|---|
| 1877 | |
|---|
| 1878 | /* |
|---|
| 1879 | * allocate and init rings, descriptors etc. |
|---|
| 1880 | */ |
|---|
| 1881 | static int |
|---|
| 1882 | ag7100_tx_alloc(ag7100_mac_t *mac) |
|---|
| 1883 | { |
|---|
| 1884 | ag7100_ring_t *r = &mac->mac_txring; |
|---|
| 1885 | ag7100_desc_t *ds; |
|---|
| 1886 | int i, next; |
|---|
| 1887 | |
|---|
| 1888 | if (ag7100_ring_alloc(r, AG7100_TX_DESC_CNT)) |
|---|
| 1889 | return 1; |
|---|
| 1890 | |
|---|
| 1891 | ag7100_trc(r->ring_desc,"ring_desc"); |
|---|
| 1892 | |
|---|
| 1893 | ds = r->ring_desc; |
|---|
| 1894 | for(i = 0; i < r->ring_nelem; i++ ) |
|---|
| 1895 | { |
|---|
| 1896 | ag7100_trc_new(ds,"tx alloc ds"); |
|---|
| 1897 | next = (i == (r->ring_nelem - 1)) ? 0 : (i + 1); |
|---|
| 1898 | ds[i].next_desc = ag7100_desc_dma_addr(r, &ds[next]); |
|---|
| 1899 | ag7100_tx_own(&ds[i]); |
|---|
| 1900 | } |
|---|
| 1901 | |
|---|
| 1902 | return 0; |
|---|
| 1903 | } |
|---|
| 1904 | |
|---|
| 1905 | static int |
|---|
| 1906 | ag7100_rx_alloc(ag7100_mac_t *mac) |
|---|
| 1907 | { |
|---|
| 1908 | ag7100_ring_t *r = &mac->mac_rxring; |
|---|
| 1909 | ag7100_desc_t *ds; |
|---|
| 1910 | int i, next, tail = r->ring_tail; |
|---|
| 1911 | ag7100_buffer_t *bf; |
|---|
| 1912 | |
|---|
| 1913 | if (ag7100_ring_alloc(r, AG7100_RX_DESC_CNT)) |
|---|
| 1914 | return 1; |
|---|
| 1915 | |
|---|
| 1916 | ag7100_trc(r->ring_desc,"ring_desc"); |
|---|
| 1917 | |
|---|
| 1918 | ds = r->ring_desc; |
|---|
| 1919 | for(i = 0; i < r->ring_nelem; i++ ) |
|---|
| 1920 | { |
|---|
| 1921 | next = (i == (r->ring_nelem - 1)) ? 0 : (i + 1); |
|---|
| 1922 | ds[i].next_desc = ag7100_desc_dma_addr(r, &ds[next]); |
|---|
| 1923 | } |
|---|
| 1924 | |
|---|
| 1925 | for (i = 0; i < AG7100_RX_DESC_CNT; i++) |
|---|
| 1926 | { |
|---|
| 1927 | bf = &r->ring_buffer[tail]; |
|---|
| 1928 | ds = &r->ring_desc[tail]; |
|---|
| 1929 | |
|---|
| 1930 | bf->buf_pkt = ag7100_buffer_alloc(); |
|---|
| 1931 | if (!bf->buf_pkt) |
|---|
| 1932 | goto error; |
|---|
| 1933 | |
|---|
| 1934 | dma_cache_inv((unsigned long)bf->buf_pkt->data, AG7100_RX_BUF_SIZE); |
|---|
| 1935 | ds->pkt_start_addr = virt_to_phys(bf->buf_pkt->data); |
|---|
| 1936 | |
|---|
| 1937 | ag7100_rx_give_to_dma(ds); |
|---|
| 1938 | ag7100_ring_incr(tail); |
|---|
| 1939 | } |
|---|
| 1940 | |
|---|
| 1941 | return 0; |
|---|
| 1942 | error: |
|---|
| 1943 | printk(MODULE_NAME ": unable to allocate rx\n"); |
|---|
| 1944 | ag7100_rx_free(mac); |
|---|
| 1945 | return 1; |
|---|
| 1946 | } |
|---|
| 1947 | |
|---|
| 1948 | static void |
|---|
| 1949 | ag7100_tx_free(ag7100_mac_t *mac) |
|---|
| 1950 | { |
|---|
| 1951 | ag7100_ring_release(mac, &mac->mac_txring); |
|---|
| 1952 | ag7100_ring_free(&mac->mac_txring); |
|---|
| 1953 | } |
|---|
| 1954 | |
|---|
| 1955 | static void |
|---|
| 1956 | ag7100_rx_free(ag7100_mac_t *mac) |
|---|
| 1957 | { |
|---|
| 1958 | ag7100_ring_release(mac, &mac->mac_rxring); |
|---|
| 1959 | ag7100_ring_free(&mac->mac_rxring); |
|---|
| 1960 | } |
|---|
| 1961 | |
|---|
| 1962 | static int |
|---|
| 1963 | ag7100_ring_alloc(ag7100_ring_t *r, int count) |
|---|
| 1964 | { |
|---|
| 1965 | int desc_alloc_size, buf_alloc_size; |
|---|
| 1966 | |
|---|
| 1967 | desc_alloc_size = sizeof(ag7100_desc_t) * count; |
|---|
| 1968 | buf_alloc_size = sizeof(ag7100_buffer_t) * count; |
|---|
| 1969 | |
|---|
| 1970 | memset(r, 0, sizeof(ag7100_ring_t)); |
|---|
| 1971 | |
|---|
| 1972 | r->ring_buffer = (ag7100_buffer_t *)kmalloc(buf_alloc_size, GFP_KERNEL); |
|---|
| 1973 | printk("%s Allocated %d at 0x%lx\n",__func__,buf_alloc_size,(unsigned long) r->ring_buffer); |
|---|
| 1974 | if (!r->ring_buffer) |
|---|
| 1975 | { |
|---|
| 1976 | printk(MODULE_NAME ": unable to allocate buffers\n"); |
|---|
| 1977 | return 1; |
|---|
| 1978 | } |
|---|
| 1979 | |
|---|
| 1980 | r->ring_desc = (ag7100_desc_t *)dma_alloc_coherent(NULL, |
|---|
| 1981 | desc_alloc_size, |
|---|
| 1982 | &r->ring_desc_dma, |
|---|
| 1983 | GFP_DMA); |
|---|
| 1984 | if (! r->ring_desc) |
|---|
| 1985 | { |
|---|
| 1986 | printk(MODULE_NAME ": unable to allocate coherent descs\n"); |
|---|
| 1987 | kfree(r->ring_buffer); |
|---|
| 1988 | printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) r->ring_buffer); |
|---|
| 1989 | return 1; |
|---|
| 1990 | } |
|---|
| 1991 | |
|---|
| 1992 | memset(r->ring_buffer, 0, buf_alloc_size); |
|---|
| 1993 | memset(r->ring_desc, 0, desc_alloc_size); |
|---|
| 1994 | r->ring_nelem = count; |
|---|
| 1995 | |
|---|
| 1996 | return 0; |
|---|
| 1997 | } |
|---|
| 1998 | |
|---|
| 1999 | static void |
|---|
| 2000 | ag7100_ring_release(ag7100_mac_t *mac, ag7100_ring_t *r) |
|---|
| 2001 | { |
|---|
| 2002 | int i; |
|---|
| 2003 | |
|---|
| 2004 | for(i = 0; i < r->ring_nelem; i++) |
|---|
| 2005 | if (r->ring_buffer[i].buf_pkt) |
|---|
| 2006 | ag7100_buffer_free(r->ring_buffer[i].buf_pkt); |
|---|
| 2007 | } |
|---|
| 2008 | |
|---|
| 2009 | static void |
|---|
| 2010 | ag7100_ring_free(ag7100_ring_t *r) |
|---|
| 2011 | { |
|---|
| 2012 | dma_free_coherent(NULL, sizeof(ag7100_desc_t)*r->ring_nelem, r->ring_desc, |
|---|
| 2013 | r->ring_desc_dma); |
|---|
| 2014 | kfree(r->ring_buffer); |
|---|
| 2015 | printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) r->ring_buffer); |
|---|
| 2016 | } |
|---|
| 2017 | |
|---|
| 2018 | /* |
|---|
| 2019 | * Error timers |
|---|
| 2020 | */ |
|---|
| 2021 | static void |
|---|
| 2022 | ag7100_oom_timer(unsigned long data) |
|---|
| 2023 | { |
|---|
| 2024 | ag7100_mac_t *mac = (ag7100_mac_t *)data; |
|---|
| 2025 | int val; |
|---|
| 2026 | |
|---|
| 2027 | ag7100_trc(data,"data"); |
|---|
| 2028 | ag7100_rx_replenish(mac); |
|---|
| 2029 | if (ag7100_rx_ring_full(mac)) |
|---|
| 2030 | { |
|---|
| 2031 | val = mod_timer(&mac->mac_oom_timer, jiffies+1); |
|---|
| 2032 | assert(!val); |
|---|
| 2033 | } |
|---|
| 2034 | else |
|---|
| 2035 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 2036 | netif_rx_schedule(mac->mac_dev, &mac->mac_napi); |
|---|
| 2037 | #else |
|---|
| 2038 | netif_rx_schedule(mac->mac_dev); |
|---|
| 2039 | #endif |
|---|
| 2040 | } |
|---|
| 2041 | |
|---|
| 2042 | static void |
|---|
| 2043 | ag7100_tx_timeout(struct net_device *dev) |
|---|
| 2044 | { |
|---|
| 2045 | ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; |
|---|
| 2046 | ag7100_trc(dev,"dev"); |
|---|
| 2047 | printk("%s\n",__func__); |
|---|
| 2048 | /* |
|---|
| 2049 | * Do the reset outside of interrupt context |
|---|
| 2050 | */ |
|---|
| 2051 | schedule_work(&mac->mac_tx_timeout); |
|---|
| 2052 | } |
|---|
| 2053 | |
|---|
| 2054 | |
|---|
| 2055 | static void |
|---|
| 2056 | ag7100_tx_timeout_task(struct work_struct *work) |
|---|
| 2057 | { |
|---|
| 2058 | ag7100_mac_t *mac = container_of(work, ag7100_mac_t, mac_tx_timeout); |
|---|
| 2059 | ag7100_trc(mac,"mac"); |
|---|
| 2060 | ag7100_stop(mac->mac_dev); |
|---|
| 2061 | ag7100_open(mac->mac_dev); |
|---|
| 2062 | } |
|---|
| 2063 | |
|---|
| 2064 | static void |
|---|
| 2065 | ag7100_get_default_macaddr(ag7100_mac_t *mac, u8 *mac_addr) |
|---|
| 2066 | { |
|---|
| 2067 | /* |
|---|
| 2068 | ** Use MAC address stored in Flash. If CONFIG_AG7100_MAC_LOCATION is defined, |
|---|
| 2069 | ** it provides the physical address of where the MAC addresses are located. |
|---|
| 2070 | ** This can be a board specific location, so it's best to be part of the |
|---|
| 2071 | ** defconfig for that board. |
|---|
| 2072 | ** |
|---|
| 2073 | ** The default locations assume the last sector in flash. |
|---|
| 2074 | */ |
|---|
| 2075 | |
|---|
| 2076 | #ifdef CONFIG_AG7100_MAC_LOCATION |
|---|
| 2077 | u8 *eep_mac_addr = (u8 *)( CONFIG_AG7100_MAC_LOCATION + (mac->mac_unit)*6); |
|---|
| 2078 | #else |
|---|
| 2079 | u8 *eep_mac_addr = (mac->mac_unit) ? AR7100_EEPROM_GE1_MAC_ADDR: |
|---|
| 2080 | AR7100_EEPROM_GE0_MAC_ADDR; |
|---|
| 2081 | #endif |
|---|
| 2082 | |
|---|
| 2083 | printk(MODULE_NAME "CHH: Mac address for unit %d\n",mac->mac_unit); |
|---|
| 2084 | printk(MODULE_NAME "CHH: %02x:%02x:%02x:%02x:%02x:%02x \n", |
|---|
| 2085 | eep_mac_addr[0],eep_mac_addr[1],eep_mac_addr[2], |
|---|
| 2086 | eep_mac_addr[3],eep_mac_addr[4],eep_mac_addr[5]); |
|---|
| 2087 | memcpy(mac_addr,eep_mac_addr,6); |
|---|
| 2088 | } |
|---|
| 2089 | |
|---|
| 2090 | static int |
|---|
| 2091 | ag7100_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
|---|
| 2092 | { |
|---|
| 2093 | #if !defined(CONFIG_ATHRS26_PHY) && !defined(CONFIG_ATHRS16_PHY) |
|---|
| 2094 | printk(MODULE_NAME ": unsupported ioctl\n"); |
|---|
| 2095 | return -EOPNOTSUPP; |
|---|
| 2096 | #else |
|---|
| 2097 | return athr_ioctl(ifr->ifr_data, cmd); |
|---|
| 2098 | #endif |
|---|
| 2099 | } |
|---|
| 2100 | |
|---|
| 2101 | static struct net_device_stats |
|---|
| 2102 | *ag7100_get_stats(struct net_device *dev) |
|---|
| 2103 | { |
|---|
| 2104 | ag7100_mac_t *mac = dev->priv; |
|---|
| 2105 | struct Qdisc *sch; |
|---|
| 2106 | int i; |
|---|
| 2107 | |
|---|
| 2108 | sch = rcu_dereference(dev->qdisc); |
|---|
| 2109 | mac->mac_net_stats.tx_dropped = sch->qstats.drops; |
|---|
| 2110 | |
|---|
| 2111 | i = ag7100_get_rx_count(mac) - mac->net_rx_packets; |
|---|
| 2112 | if (i<0) |
|---|
| 2113 | i=0; |
|---|
| 2114 | |
|---|
| 2115 | mac->mac_net_stats.rx_missed_errors = i; |
|---|
| 2116 | |
|---|
| 2117 | return &mac->mac_net_stats; |
|---|
| 2118 | } |
|---|
| 2119 | |
|---|
| 2120 | static void |
|---|
| 2121 | ag7100_vet_tx_len_per_pkt(unsigned int *len) |
|---|
| 2122 | { |
|---|
| 2123 | unsigned int l; |
|---|
| 2124 | |
|---|
| 2125 | /* make it into words */ |
|---|
| 2126 | l = *len & ~3; |
|---|
| 2127 | |
|---|
| 2128 | /* |
|---|
| 2129 | * Not too small |
|---|
| 2130 | */ |
|---|
| 2131 | if (l < AG7100_TX_MIN_DS_LEN) |
|---|
| 2132 | l = AG7100_TX_MIN_DS_LEN; |
|---|
| 2133 | else |
|---|
| 2134 | /* Avoid len where we know we will deadlock, that |
|---|
| 2135 | * is the range between fif_len/2 and the MTU size |
|---|
| 2136 | */ |
|---|
| 2137 | if (l > (AG7100_TX_FIFO_LEN/2)) |
|---|
| 2138 | { |
|---|
| 2139 | if (l < AG7100_TX_MTU_LEN) |
|---|
| 2140 | { |
|---|
| 2141 | l = AG7100_TX_MTU_LEN; |
|---|
| 2142 | } |
|---|
| 2143 | else if (l > AG7100_TX_MAX_DS_LEN) |
|---|
| 2144 | { |
|---|
| 2145 | l = AG7100_TX_MAX_DS_LEN; |
|---|
| 2146 | } |
|---|
| 2147 | *len = l; |
|---|
| 2148 | } |
|---|
| 2149 | } |
|---|
| 2150 | |
|---|
| 2151 | /* |
|---|
| 2152 | * All allocations (except irq and rings). |
|---|
| 2153 | */ |
|---|
| 2154 | static int __init |
|---|
| 2155 | ag7100_init(void) |
|---|
| 2156 | { |
|---|
| 2157 | int i; |
|---|
| 2158 | struct net_device *dev; |
|---|
| 2159 | ag7100_mac_t *mac; |
|---|
| 2160 | uint32_t mask; |
|---|
| 2161 | |
|---|
| 2162 | /* |
|---|
| 2163 | * tx_len_per_ds is the number of bytes per data transfer in word increments. |
|---|
| 2164 | * |
|---|
| 2165 | * If the value is 0 than we default the value to a known good value based |
|---|
| 2166 | * on benchmarks. Otherwise we use the value specified - within some |
|---|
| 2167 | * cosntraints of course. |
|---|
| 2168 | * |
|---|
| 2169 | * Tested working values are 256, 512, 768, 1024 & 1536. |
|---|
| 2170 | * |
|---|
| 2171 | * A value of 256 worked best in all benchmarks. That is the default. |
|---|
| 2172 | * |
|---|
| 2173 | */ |
|---|
| 2174 | |
|---|
| 2175 | /* Tested 256, 512, 768, 1024, 1536 OK, 1152 and 1280 failed*/ |
|---|
| 2176 | if (0 == tx_len_per_ds) |
|---|
| 2177 | tx_len_per_ds = CONFIG_AG7100_LEN_PER_TX_DS; |
|---|
| 2178 | |
|---|
| 2179 | ag7100_vet_tx_len_per_pkt( &tx_len_per_ds); |
|---|
| 2180 | |
|---|
| 2181 | printk(MODULE_NAME ": Length per segment %d\n", tx_len_per_ds); |
|---|
| 2182 | |
|---|
| 2183 | /* |
|---|
| 2184 | * Compute the number of descriptors for an MTU |
|---|
| 2185 | */ |
|---|
| 2186 | #ifndef CONFIG_AR9100 |
|---|
| 2187 | tx_max_desc_per_ds_pkt = AG7100_TX_MAX_DS_LEN / tx_len_per_ds; |
|---|
| 2188 | if (AG7100_TX_MAX_DS_LEN % tx_len_per_ds) tx_max_desc_per_ds_pkt++; |
|---|
| 2189 | #else |
|---|
| 2190 | tx_max_desc_per_ds_pkt =1; |
|---|
| 2191 | #endif |
|---|
| 2192 | |
|---|
| 2193 | printk(MODULE_NAME ": Max segments per packet %d\n", tx_max_desc_per_ds_pkt); |
|---|
| 2194 | printk(MODULE_NAME ": Max tx descriptor count %d\n", AG7100_TX_DESC_CNT); |
|---|
| 2195 | printk(MODULE_NAME ": Max rx descriptor count %d\n", AG7100_RX_DESC_CNT); |
|---|
| 2196 | |
|---|
| 2197 | /* |
|---|
| 2198 | * Let hydra know how much to put into the fifo in words (for tx) |
|---|
| 2199 | */ |
|---|
| 2200 | if (0 == fifo_3) |
|---|
| 2201 | fifo_3 = 0x000001ff | ((AG7100_TX_FIFO_LEN-tx_len_per_ds)/4)<<16; |
|---|
| 2202 | |
|---|
| 2203 | printk(MODULE_NAME ": fifo cfg 3 %08x\n", fifo_3); |
|---|
| 2204 | |
|---|
| 2205 | /* |
|---|
| 2206 | ** Do the rest of the initializations |
|---|
| 2207 | */ |
|---|
| 2208 | |
|---|
| 2209 | for(i = 0; i < AG7100_NMACS; i++) |
|---|
| 2210 | { |
|---|
| 2211 | mac = kmalloc(sizeof(ag7100_mac_t), GFP_KERNEL); |
|---|
| 2212 | if (!mac) |
|---|
| 2213 | { |
|---|
| 2214 | printk(MODULE_NAME ": unable to allocate mac\n"); |
|---|
| 2215 | return 1; |
|---|
| 2216 | } |
|---|
| 2217 | memset(mac, 0, sizeof(ag7100_mac_t)); |
|---|
| 2218 | |
|---|
| 2219 | mac->mac_unit = i; |
|---|
| 2220 | mac->mac_base = ag7100_mac_base(i); |
|---|
| 2221 | mac->mac_irq = ag7100_mac_irq(i); |
|---|
| 2222 | ag7100_macs[i] = mac; |
|---|
| 2223 | spin_lock_init(&mac->mac_lock); |
|---|
| 2224 | /* |
|---|
| 2225 | * out of memory timer |
|---|
| 2226 | */ |
|---|
| 2227 | init_timer(&mac->mac_oom_timer); |
|---|
| 2228 | mac->mac_oom_timer.data = (unsigned long)mac; |
|---|
| 2229 | mac->mac_oom_timer.function = ag7100_oom_timer; |
|---|
| 2230 | /* |
|---|
| 2231 | * watchdog task |
|---|
| 2232 | */ |
|---|
| 2233 | INIT_WORK(&mac->mac_tx_timeout, ag7100_tx_timeout_task); |
|---|
| 2234 | |
|---|
| 2235 | dev = alloc_etherdev(0); |
|---|
| 2236 | if (!dev) |
|---|
| 2237 | { |
|---|
| 2238 | kfree(mac); |
|---|
| 2239 | printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) mac); |
|---|
| 2240 | printk(MODULE_NAME ": unable to allocate etherdev\n"); |
|---|
| 2241 | return 1; |
|---|
| 2242 | } |
|---|
| 2243 | |
|---|
| 2244 | mac->mac_dev = dev; |
|---|
| 2245 | dev->get_stats = ag7100_get_stats; |
|---|
| 2246 | dev->open = ag7100_open; |
|---|
| 2247 | dev->stop = ag7100_stop; |
|---|
| 2248 | dev->hard_start_xmit = ag7100_hard_start; |
|---|
| 2249 | #if defined(CONFIG_ATHRS26_PHY) || defined(CONFIG_ATHRS16_PHY) |
|---|
| 2250 | dev->do_ioctl = ag7100_do_ioctl; |
|---|
| 2251 | #else |
|---|
| 2252 | dev->do_ioctl = NULL; |
|---|
| 2253 | #endif |
|---|
| 2254 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) |
|---|
| 2255 | netif_napi_add(dev, &mac->mac_napi, ag7100_poll, AG7100_NAPI_WEIGHT); |
|---|
| 2256 | #else |
|---|
| 2257 | dev->poll = ag7100_poll; |
|---|
| 2258 | dev->weight = AG7100_NAPI_WEIGHT; |
|---|
| 2259 | #endif |
|---|
| 2260 | dev->tx_timeout = ag7100_tx_timeout; |
|---|
| 2261 | dev->priv = mac; |
|---|
| 2262 | |
|---|
| 2263 | #ifdef CONFIG_BUFFALO // { append by BUFFALO 2008.09.19 |
|---|
| 2264 | |
|---|
| 2265 | #ifdef CONFIG_TPLINK |
|---|
| 2266 | switch(rtl_chip_type_select()) |
|---|
| 2267 | { |
|---|
| 2268 | case CHIP_TYPE_RTL8366SR: |
|---|
| 2269 | rtl_funcs.phy_setup = rtl8366sr_phy_setup; |
|---|
| 2270 | rtl_funcs.phy_is_up = rtl8366sr_phy_is_up; |
|---|
| 2271 | rtl_funcs.phy_speed = rtl8366sr_phy_speed; |
|---|
| 2272 | rtl_funcs.phy_is_fdx = rtl8366sr_phy_is_fdx; |
|---|
| 2273 | rtl_funcs.get_link_status = rtl8366sr_get_link_status; |
|---|
| 2274 | e1000_pll = e1000sr_pll; |
|---|
| 2275 | e100_pll = e100sr_pll; |
|---|
| 2276 | e10_pll = e10sr_pll; |
|---|
| 2277 | break; |
|---|
| 2278 | case CHIP_TYPE_RTL8366RB: |
|---|
| 2279 | default: |
|---|
| 2280 | rtl_funcs.phy_setup = rtl8366rb_phy_setup; |
|---|
| 2281 | rtl_funcs.phy_is_up = rtl8366rb_phy_is_up; |
|---|
| 2282 | rtl_funcs.phy_speed = rtl8366rb_phy_speed; |
|---|
| 2283 | rtl_funcs.phy_is_fdx = rtl8366rb_phy_is_fdx; |
|---|
| 2284 | rtl_funcs.get_link_status = rtl8366rb_get_link_status; |
|---|
| 2285 | e1000_pll = e1000rb_pll; |
|---|
| 2286 | e100_pll = e100rb_pll; |
|---|
| 2287 | e10_pll = e10rb_pll; |
|---|
| 2288 | break; |
|---|
| 2289 | } |
|---|
| 2290 | #else |
|---|
| 2291 | switch(rtl_chip_type_select()) |
|---|
| 2292 | { |
|---|
| 2293 | case CHIP_TYPE_RTL8366RB: |
|---|
| 2294 | rtl_funcs.phy_setup = rtl8366rb_phy_setup; |
|---|
| 2295 | rtl_funcs.phy_is_up = rtl8366rb_phy_is_up; |
|---|
| 2296 | rtl_funcs.phy_speed = rtl8366rb_phy_speed; |
|---|
| 2297 | rtl_funcs.phy_is_fdx = rtl8366rb_phy_is_fdx; |
|---|
| 2298 | rtl_funcs.get_link_status = rtl8366rb_get_link_status; |
|---|
| 2299 | e1000_pll = e1000rb_pll; |
|---|
| 2300 | e100_pll = e100rb_pll; |
|---|
| 2301 | e10_pll = e10rb_pll; |
|---|
| 2302 | break; |
|---|
| 2303 | case CHIP_TYPE_RTL8366SR: |
|---|
| 2304 | default: |
|---|
| 2305 | rtl_funcs.phy_setup = rtl8366sr_phy_setup; |
|---|
| 2306 | rtl_funcs.phy_is_up = rtl8366sr_phy_is_up; |
|---|
| 2307 | rtl_funcs.phy_speed = rtl8366sr_phy_speed; |
|---|
| 2308 | rtl_funcs.phy_is_fdx = rtl8366sr_phy_is_fdx; |
|---|
| 2309 | rtl_funcs.get_link_status = rtl8366sr_get_link_status; |
|---|
| 2310 | e1000_pll = e1000sr_pll; |
|---|
| 2311 | e100_pll = e100sr_pll; |
|---|
| 2312 | e10_pll = e10sr_pll; |
|---|
| 2313 | break; |
|---|
| 2314 | } |
|---|
| 2315 | |
|---|
| 2316 | |
|---|
| 2317 | #endif |
|---|
| 2318 | #else //CONFIG_BUFFALO // |
|---|
| 2319 | #ifdef CONFIG_CAMEO_REALTEK_PHY |
|---|
| 2320 | rtl_chip_type_select(); |
|---|
| 2321 | #endif |
|---|
| 2322 | #endif |
|---|
| 2323 | ag7100_get_default_macaddr(mac, dev->dev_addr); |
|---|
| 2324 | |
|---|
| 2325 | if (register_netdev(dev)) |
|---|
| 2326 | { |
|---|
| 2327 | printk(MODULE_NAME ": register netdev failed\n"); |
|---|
| 2328 | goto failed; |
|---|
| 2329 | } |
|---|
| 2330 | #ifdef CONFIG_PHY_LAYER |
|---|
| 2331 | ag7100_mdiobus_setup(i,dev); |
|---|
| 2332 | #endif |
|---|
| 2333 | |
|---|
| 2334 | netif_carrier_off(dev); |
|---|
| 2335 | |
|---|
| 2336 | #ifdef CONFIG_AR9100 |
|---|
| 2337 | ag7100_reg_rmw_set(mac, AG7100_MAC_CFG1, AG7100_MAC_CFG1_SOFT_RST |
|---|
| 2338 | | AG7100_MAC_CFG1_RX_RST | AG7100_MAC_CFG1_TX_RST); |
|---|
| 2339 | #else |
|---|
| 2340 | ag7100_reg_rmw_set(mac, AG7100_MAC_CFG1, AG7100_MAC_CFG1_SOFT_RST); |
|---|
| 2341 | #endif |
|---|
| 2342 | udelay(20); |
|---|
| 2343 | mask = ag7100_reset_mask(mac->mac_unit); |
|---|
| 2344 | |
|---|
| 2345 | /* |
|---|
| 2346 | * put into reset, hold, pull out. |
|---|
| 2347 | */ |
|---|
| 2348 | ar7100_reg_rmw_set(AR7100_RESET, mask); |
|---|
| 2349 | mdelay(100); |
|---|
| 2350 | ar7100_reg_rmw_clear(AR7100_RESET, mask); |
|---|
| 2351 | mdelay(100); |
|---|
| 2352 | |
|---|
| 2353 | } |
|---|
| 2354 | |
|---|
| 2355 | ag7100_trc_init(); |
|---|
| 2356 | |
|---|
| 2357 | #ifdef CONFIG_AR9100 |
|---|
| 2358 | #define AP83_BOARD_NUM_ADDR ((char *)0xbf7f1244) |
|---|
| 2359 | |
|---|
| 2360 | board_version = (AP83_BOARD_NUM_ADDR[0] - '0') + |
|---|
| 2361 | ((AP83_BOARD_NUM_ADDR[1] - '0') * 10); |
|---|
| 2362 | #endif |
|---|
| 2363 | |
|---|
| 2364 | #if defined(CONFIG_ATHRS26_PHY) |
|---|
| 2365 | athrs26_reg_dev(ag7100_macs); |
|---|
| 2366 | #endif |
|---|
| 2367 | |
|---|
| 2368 | return 0; |
|---|
| 2369 | |
|---|
| 2370 | failed: |
|---|
| 2371 | for(i = 0; i < AG7100_NMACS; i++) |
|---|
| 2372 | { |
|---|
| 2373 | if (!ag7100_macs[i]) |
|---|
| 2374 | continue; |
|---|
| 2375 | if (ag7100_macs[i]->mac_dev) |
|---|
| 2376 | free_netdev(ag7100_macs[i]->mac_dev); |
|---|
| 2377 | kfree(ag7100_macs[i]); |
|---|
| 2378 | printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) ag7100_macs[i]); |
|---|
| 2379 | } |
|---|
| 2380 | return 1; |
|---|
| 2381 | } |
|---|
| 2382 | |
|---|
| 2383 | static void __exit |
|---|
| 2384 | ag7100_cleanup(void) |
|---|
| 2385 | { |
|---|
| 2386 | int i; |
|---|
| 2387 | |
|---|
| 2388 | for(i = 0; i < AG7100_NMACS; i++) |
|---|
| 2389 | { |
|---|
| 2390 | unregister_netdev(ag7100_macs[i]->mac_dev); |
|---|
| 2391 | free_netdev(ag7100_macs[i]->mac_dev); |
|---|
| 2392 | kfree(ag7100_macs[i]); |
|---|
| 2393 | printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) ag7100_macs[i]); |
|---|
| 2394 | } |
|---|
| 2395 | printk(MODULE_NAME ": cleanup done\n"); |
|---|
| 2396 | } |
|---|
| 2397 | |
|---|
| 2398 | module_init(ag7100_init); |
|---|
| 2399 | module_exit(ag7100_cleanup); |
|---|