Axis Area
Public Area
Special pages
NOTE
This patch applies to the CRIS V32 (ETRAX FS) Ethernet driver in the Linux 2.6 kernel supplied in the 2.10 software distribution (os-linux-2.6-tag–devboard-R2_10-4).
Index: os/linux-2.6/drivers/net/cris/eth_v32.c =================================================================== --- os/linux-2.6/drivers/net/cris/eth_v32.c 6 Feb 2007 10:10:37 -0000 1.96 +++ os/linux-2.6/drivers/net/cris/eth_v32.c 4 Sep 2007 11:19:32 -0000 1.96.2.1 @@ -34,7 +34,11 @@ #include <asm/arch/hwregs/reg_rdwr.h> #include <asm/arch/hwregs/dma.h> #include <asm/arch/hwregs/eth_defs.h> +#ifdef CONFIG_ETRAXFS #include <asm/arch/hwregs/config_defs.h> +#else +#include <asm/arch/hwregs/clkgen_defs.h> +#endif #include <asm/arch/hwregs/intr_vect_defs.h> #include <asm/system.h> #include <asm/bitops.h> @@ -45,6 +49,13 @@ #include "eth_v32.h" +#ifndef CONFIG_ETRAXFS +#define ETH0_INTR_VECT ETH_INTR_VECT +#define ETH1_INTR_VECT ETH_INTR_VECT +#define regi_eth0 regi_eth +#define regi_eth1 regi_ +#endif + #define DEBUG(x) #define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) @@ -53,10 +64,9 @@ static int use_network_leds = 1; static void update_rx_stats(struct crisv32_ethernet_local *np); static void update_tx_stats(struct crisv32_ethernet_local *np); +static int crisv32_eth_poll(struct net_device *dev, int *budget); static void crisv32_eth_setup_controller(struct net_device *dev); static int crisv32_eth_request_irqdma(struct net_device *dev); -static void crisv32_eth_init_rings(struct net_device *dev); -static void crisv32_eth_reset_rings(struct net_device *dev); static void crisv32_ethernet_bug(struct net_device *dev); /* @@ -77,6 +87,8 @@ struct transceiver_ops transceivers[] = {0x04de, intel_check_speed, intel_check_duplex}, /* National Semiconductor DP83865 */ {0x0017, national_check_speed, national_check_duplex}, + /* Vitesse VCS8641 */ + {0x01c1, vitesse_check_speed, vitesse_check_duplex}, /* Generic, must be last. */ {0x0000, generic_check_speed, generic_check_duplex} }; @@ -84,6 +96,11 @@ struct transceiver_ops transceivers[] = static struct net_device *crisv32_dev[2]; static struct crisv32_eth_leds *crisv32_leds[3]; +/* Default MAC address for interface 0. + * The real one will be set later. */ +static struct sockaddr default_mac_iface0 = + {0, {0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00}}; + #ifdef CONFIG_CPU_FREQ static int crisv32_ethernet_freq_notifier(struct notifier_block *nb, unsigned long val, @@ -215,8 +232,6 @@ crisv32_eth_setup_controller(struct net_ { struct crisv32_ethernet_local *np = netdev_priv(dev); - reg_config_rw_pad_ctrl pad_ctrl; - reg_eth_rw_tr_ctrl tr_ctrl = { .retry = regk_eth_yes, .pad = regk_eth_yes, @@ -257,54 +272,26 @@ crisv32_eth_setup_controller(struct net_ udelay(500); /* done */ + +#ifdef CONFIG_ETRAXFS + reg_config_rw_pad_ctrl pad_ctrl; pad_ctrl = REG_RD(config, regi_config, rw_pad_ctrl); pad_ctrl.phyrst_n = 1; REG_WR(config, regi_config, rw_pad_ctrl, pad_ctrl); +#else + gen_ctrl.phyrst_n = 1; + REG_WR(eth, np->eth_inst, rw_gen_ctrl, gen_ctrl); +#endif /* Let the PHY reset (RESET_WAIT) */ udelay(200); - crisv32_eth_probe_transceiver(dev); -} - -static void __init -crisv32_eth_init_rings(struct net_device *dev) -{ - struct crisv32_ethernet_local *np = netdev_priv(dev); - int i; - - /* Initialise receive descriptors for interface. */ - for (i = 0; i < NBR_RX_DESC; i++) { - struct sk_buff *skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE); - - np->dma_rx_descr_list[i].skb = skb; - np->dma_rx_descr_list[i].descr.buf = - (char*)virt_to_phys(skb->data); - np->dma_rx_descr_list[i].descr.after = - (char*)virt_to_phys(skb->data + MAX_MEDIA_DATA_SIZE); - - np->dma_rx_descr_list[i].descr.eol = 0; - np->dma_rx_descr_list[i].descr.in_eop = 0; - np->dma_rx_descr_list[i].descr.next = - (void *) virt_to_phys(&np->dma_rx_descr_list[i + 1].descr); - } - /* bend the list into a ring */ - np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.next = - (void *) virt_to_phys(&np->dma_rx_descr_list[0].descr); - - /* Initialize transmit descriptors. */ - for (i = 0; i < NBR_TX_DESC; i++) { - np->dma_tx_descr_list[i].descr.wait = 1; - np->dma_tx_descr_list[i].descr.eol = 0; - np->dma_tx_descr_list[i].descr.out_eop = 0; - np->dma_tx_descr_list[i].descr.next = - (void*)virt_to_phys(&np->dma_tx_descr_list[i+1].descr); + if(crisv32_eth_probe_transceiver(dev)) { + printk("%s: No transceiver found, removing interface\n", + dev->name); + unregister_netdev(dev); + /* We should probably do more here... */ } - /* bend the list into a ring */ - np->dma_tx_descr_list[NBR_TX_DESC - 1].descr.next = - (void *) virt_to_phys(&np->dma_tx_descr_list[0].descr); - - crisv32_eth_reset_rings(dev); } static void @@ -366,6 +353,8 @@ crisv32_eth_reset_rings(struct net_devic np->prev_rx_desc = &np->dma_rx_descr_list[NBR_RX_DESC - 1]; np->last_rx_desc = np->prev_rx_desc; np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.eol = 1; + /* ready to accept new packets. */ + np->new_rx_package = 1; /* reset tx-ring */ np->dma_tx_descr_list[0].descr.buf = @@ -388,6 +377,93 @@ crisv32_eth_reset_rings(struct net_devic (void *)virt_to_phys(&np->dma_tx_descr_list[0].descr); } +/* + * Really advance the receive ring. RX interrupts must be off. + */ +static void +__crisv32_eth_rx_ring_advance(struct crisv32_ethernet_local *np) +{ + if (np->newbuf) + np->active_rx_desc->descr.buf = (void *) np->newbuf; + np->active_rx_desc->descr.after = + np->active_rx_desc->descr.buf + MAX_MEDIA_DATA_SIZE; + np->active_rx_desc->descr.eol = 1; + np->active_rx_desc->descr.in_eop = 0; + np->active_rx_desc = phys_to_virt((int)np->active_rx_desc->descr.next); + barrier(); + np->prev_rx_desc->descr.eol = 0; + + /* Workaround cache bug. */ + flush_dma_descr(&np->prev_rx_desc->descr, 0); + np->prev_rx_desc = phys_to_virt((int)np->prev_rx_desc->descr.next); + flush_dma_descr(&np->prev_rx_desc->descr, 1); +} + +/* + * Advance the receive ring. RX interrupts must be off. + */ +static inline void +crisv32_eth_rx_ring_advance(struct crisv32_ethernet_local *np) +{ + /* + * When the input DMA reaches eol precaution must be taken, otherwise + * the DMA could stop. The problem occurs if the eol flag is re-placed + * on the descriptor that the DMA stands on before the DMA proceed to + * the next descriptor. This case could, for example, happen if there + * is a traffic burst and then the network goes silent. To prevent this + * we make sure that we do not set the eol flag on the descriptor that + * the DMA stands on. + */ + if(virt_to_phys(&np->active_rx_desc->descr) != + REG_RD_INT(dma, np->dma_in_inst, rw_saved_data)) { + /* Now really advance the ring one step. */ + __crisv32_eth_rx_ring_advance(np); + } else { + /* delay the advancing of the ring. */ + np->new_rx_package = 0; + } +} + +static void __init +crisv32_eth_init_rings(struct net_device *dev) +{ + struct crisv32_ethernet_local *np = netdev_priv(dev); + int i; + + /* Initialise receive descriptors for interface. */ + for (i = 0; i < NBR_RX_DESC; i++) { + struct sk_buff *skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE); + + np->dma_rx_descr_list[i].skb = skb; + np->dma_rx_descr_list[i].descr.buf = + (char*)virt_to_phys(skb->data); + np->dma_rx_descr_list[i].descr.after = + (char*)virt_to_phys(skb->data + MAX_MEDIA_DATA_SIZE); + + np->dma_rx_descr_list[i].descr.eol = 0; + np->dma_rx_descr_list[i].descr.in_eop = 0; + np->dma_rx_descr_list[i].descr.next = + (void *) virt_to_phys(&np->dma_rx_descr_list[i + 1].descr); + } + /* bend the list into a ring */ + np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.next = + (void *) virt_to_phys(&np->dma_rx_descr_list[0].descr); + + /* Initialize transmit descriptors. */ + for (i = 0; i < NBR_TX_DESC; i++) { + np->dma_tx_descr_list[i].descr.wait = 1; + np->dma_tx_descr_list[i].descr.eol = 0; + np->dma_tx_descr_list[i].descr.out_eop = 0; + np->dma_tx_descr_list[i].descr.next = + (void*)virt_to_phys(&np->dma_tx_descr_list[i+1].descr); + } + /* bend the list into a ring */ + np->dma_tx_descr_list[NBR_TX_DESC - 1].descr.next = + (void *) virt_to_phys(&np->dma_tx_descr_list[0].descr); + + crisv32_eth_reset_rings(dev); +} + static void __init crisv32_init_leds(int ledgrp, struct net_device* dev) { @@ -400,15 +476,18 @@ crisv32_init_leds(int ledgrp, struct net return; } - crisv32_leds[ledgrp] = kmalloc(sizeof(struct crisv32_eth_leds),GFP_KERNEL); + crisv32_leds[ledgrp] = kmalloc(sizeof(struct crisv32_eth_leds), + GFP_KERNEL); crisv32_leds[ledgrp]->ledgrp = ledgrp; crisv32_leds[ledgrp]->led_active = 0; - /* NOTE: Should this value be set to zero as the jiffies timer can wrap? */ + /* NOTE: Should this value be set to zero as the jiffies timer + can wrap? */ crisv32_leds[ledgrp]->led_next_time = jiffies; crisv32_leds[ledgrp]->clear_led_timer = timer_init; - crisv32_leds[ledgrp]->clear_led_timer.function = crisv32_clear_network_leds; + crisv32_leds[ledgrp]->clear_led_timer.function = + crisv32_clear_network_leds; crisv32_leds[ledgrp]->clear_led_timer.data = (unsigned long) dev; spin_lock_init(&crisv32_leds[ledgrp]->led_lock); @@ -425,13 +504,26 @@ crisv32_ethernet_init(void) printk("ETRAX FS 10/100MBit ethernet v0.01 (c)" " 2003 Axis Communications AB\n"); +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + { + reg_clkgen_rw_clk_ctrl clk_ctrl = REG_RD(clkgen, regi_clkgen, + rw_clk_ctrl); + clk_ctrl.eth = clk_ctrl.dma0_1_eth = regk_clkgen_yes; + REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); + } +#endif #ifdef CONFIG_ETRAX_ETHERNET_IFACE0 { int iface0 = 0; - /* Default MAC address for interface 0. - * The real one will be set later. */ - static struct sockaddr default_mac_iface0 = - {0, {0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00}}; + +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + if (crisv32_pinmux_alloc_fixed(pinmux_eth)) + panic("Eth pinmux\n"); +#ifdef CONFIG_ETRAX_ETHERNET_GBIT + if (crisv32_pinmux_alloc_fixed(pinmux_geth)) + panic("Eth pinmux\n"); +#endif +#endif if (!(crisv32_dev[iface0] = alloc_etherdev(sizeof *np))) return -ENOMEM; @@ -553,6 +645,14 @@ crisv32_ethernet_device_init(struct net_ #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = crisv32_netpoll; #endif + /* + * 8 skbs keeps the system very reponsive even under high load. + * At 64 the system locks, pretty much the same way as without NAPI. + * + * TODO: meassure with 2 interfaces + */ + dev->weight = 8; + dev->poll = crisv32_eth_poll; np = netdev_priv(dev); @@ -582,9 +682,12 @@ crisv32_eth_open(struct net_device *dev) { struct sockaddr mac_addr; reg_dma_rw_ack_intr ack_intr = { .data = 1,.in_eop = 1 }; - reg_dma_rw_cfg dma_cfg = { .en = 1 }; reg_eth_rw_clr_err clr_err = {.clr = regk_eth_yes}; - int intr_mask_nw = 0x1cff; + /* + * dont interrupt us at any stat counter thresholds, only at urun + * and exc_col. + */ + int intr_mask_nw = 0x1800; int eth_ack_intr = 0xffff; struct crisv32_ethernet_local *np = netdev_priv(dev); @@ -620,10 +723,11 @@ crisv32_eth_open(struct net_device *dev) crisv32_start_receiver(np); /* Prepare output DMA. */ + DMA_RESET(np->dma_out_inst); + DMA_ENABLE(np->dma_out_inst); #ifdef CONFIG_CRIS_MACH_ARTPEC3 DMA_WR_CMD(np->dma_out_inst, regk_dma_set_w_size4); #endif - REG_WR(dma, np->dma_out_inst, rw_cfg, dma_cfg); netif_start_queue(dev); crisv32_enable_tx_ints(np); @@ -633,10 +737,11 @@ crisv32_eth_open(struct net_device *dev) spin_unlock(&np->lock); /* - * We are now ready to accept transmit requeusts from the queueing + * We are now ready to accept transmit requests from the queueing * layer of the networking. */ netif_carrier_on(dev); + netif_poll_enable(dev); return 0; } @@ -650,11 +755,13 @@ crisv32_eth_close(struct net_device *dev unsigned long flags; printk(KERN_INFO "Closing %s.\n", dev->name); + spin_lock_irqsave(&np->lock, flags); /* stop the receiver before the DMA channels to avoid overruns. */ + crisv32_disable_rx_ints(np); + netif_poll_disable(dev); crisv32_stop_receiver(np); - spin_lock_irqsave(&np->lock, flags); netif_stop_queue(dev); /* Reset the TX DMA in case it has hung on something. */ @@ -669,7 +776,6 @@ crisv32_eth_close(struct net_device *dev ack_intr.data = 1; REG_WR(dma, np->dma_out_inst, rw_ack_intr, ack_intr); - crisv32_disable_rx_ints(np); ack_intr.in_eop = 1; REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr); @@ -725,42 +831,36 @@ crisv32_eth_set_mac_address(struct net_d static irqreturn_t crisv32rx_eth_interrupt(int irq, void *dev_id) { - reg_dma_r_masked_intr masked_in; - reg_dma_rw_cmd cmd = {0}; - reg_dma_rw_ack_intr ack_intr = {0}; struct net_device *dev = (struct net_device *) dev_id; struct crisv32_ethernet_local *np = netdev_priv(dev); + reg_dma_r_masked_intr masked_in; masked_in = REG_RD(dma, np->dma_in_inst, r_masked_intr); if (masked_in.in_eop) { - DEBUG(printk("EOP_IN interrupt\n")); - - /* Acknowledge input dma interrupt. */ - ack_intr.in_eop = 1; - REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr); + reg_dma_rw_ack_intr ack_intr = {0}; - np->new_rx_package = 1; - /* Check if complete packets were indeed received. */ - while (np->active_rx_desc->descr.in_eop == 1 - && np->new_rx_package) { /* - * Take out the buffer and give it to the OS, then - * allocate a new buffer to put a packet in. + * Ack the rx irq even if we are not prepared to start + * polling. This is needed to handle incomming packets + * during the stop sequence. */ - crisv32_eth_receive_packet(dev); - - /* Update number of packets received. */ - np->stats.rx_packets++; - - /* Restarts input dma. */ - cmd.cont_data = 1; - REG_WR(dma, np->dma_in_inst, rw_cmd, cmd); - - /* Acknowledge input dma interrupt. */ + ack_intr.in_eop = 1; REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr); + if (netif_rx_schedule_prep(dev)) { + crisv32_disable_rx_ints(np); + /* put us onto the poll list */ + __netif_rx_schedule(dev); } + } else { + /* Unexpected, ACK it and hope for the best. */ + reg_dma_rw_ack_intr ack_intr = {0xffff}; + printk("unexpected eth-rx irq %x\n", + REG_RD_INT(dma, np->dma_in_inst, r_masked_intr)); + ack_intr.in_eop = 0; + REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr); } + return IRQ_HANDLED; } @@ -786,8 +886,12 @@ crisv32tx_eth_interrupt(int irq, void *d dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_out_inst, rw_data)); - /* ack the interrupt */ + /* ack the interrupt, if it was active */ + if (masked_out.data) REG_WR(dma, np->dma_out_inst, rw_ack_intr, ack_intr); + else + printk("unexpected eth-tx irq %x\n", + REG_RD_INT(dma, np->dma_out_inst, r_masked_intr)); /* protect against ethernet excessive-col interrupts */ spin_lock_irqsave(&np->lock, flags); @@ -959,7 +1063,8 @@ crisv32_eth_receive_packet(struct net_de /* Activate LED */ spin_lock_irqsave(&np->leds->led_lock, flags); - if (!np->leds->led_active && time_after(jiffies, np->leds->led_next_time)) { + if (!np->leds->led_active && time_after(jiffies, + np->leds->led_next_time)) { /* light the network leds depending on the current speed. */ crisv32_set_network_leds(LED_ACTIVITY, dev); @@ -998,9 +1103,10 @@ crisv32_eth_receive_packet(struct net_de skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; /* Send the packet to the upper layer. */ - netif_rx(skb); + netif_receive_skb(skb); np->last_rx_desc = (void *) phys_to_virt(np->last_rx_desc->descr.next); + np->newbuf = 0; } else { #endif tmp = dev_alloc_skb(MAX_MEDIA_DATA_SIZE); @@ -1015,17 +1121,15 @@ crisv32_eth_receive_packet(struct net_de np->active_rx_desc->skb = tmp; skb_put(skb, length); - np->active_rx_desc->descr.buf = - (void *) virt_to_phys(np->active_rx_desc->skb->data); - np->active_rx_desc->descr.after = - np->active_rx_desc->descr.buf + MAX_MEDIA_DATA_SIZE; + np->newbuf = + virt_to_phys(np->active_rx_desc->skb->data); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; /* Send the packet to the upper layer. */ - netif_rx(skb); + netif_receive_skb(skb); np->last_rx_desc = phys_to_virt((int) np->last_rx_desc->descr.next); @@ -1033,32 +1137,77 @@ crisv32_eth_receive_packet(struct net_de #ifdef CONFIG_CRIS_MACH_ARTPEC3 } #endif + + /* Forward rotate the receive ring. */ + crisv32_eth_rx_ring_advance(np); +} + +/* + * Is there work to do in the rx-path? + */ +static inline int crisv32_has_rx_work(struct crisv32_ethernet_local *np, + dma_descr_data *active) +{ + int mw; + mw = (active->in_eop == 1 && np->new_rx_package); + return mw; +} + +/* + * NAPI poll + * + * We are allowed to poll dev->quota skb's from the rx-ring. + * Must update *budget and dev->quota. If we are done, remove us from the + * poll list and re-enable interrupts. + * + * TODO: Add tx-reclaim, + * Are there races when we re-enable ints? + */ +static int crisv32_eth_poll(struct net_device *dev, int *budget) +{ + struct crisv32_ethernet_local *np = netdev_priv(dev); + int workdone = dev->quota; + int morework; + reg_dma_rw_ack_intr ack_intr = {0}; + + ack_intr.in_eop = 1; + + if (np->new_rx_package == 0) { /* - * When the input DMA reaches eol precaution must be taken, otherwise - * the DMA could stop. The problem occurs if the eol flag is re-placed - * on the descriptor that the DMA stands on before the DMA proceed to - * the next descriptor. This case could, for example, happen if there - * is a traffic burst and then the network goes silent. To prevent this - * we make sure that we do not set the eol flag on the descriptor that - * the DMA stands on. + * In the previous round we pulled a packet from the ring but + * we didn't advance the ring due to hw DMA bug. Try to do it + * now. */ - if(virt_to_phys(&np->active_rx_desc->descr) != - REG_RD_INT(dma, np->dma_in_inst, rw_saved_data)) { - np->active_rx_desc->descr.after = - np->active_rx_desc->descr.buf + MAX_MEDIA_DATA_SIZE; - np->active_rx_desc->descr.eol = 1; - np->active_rx_desc->descr.in_eop = 0; - np->active_rx_desc = - phys_to_virt((int)np->active_rx_desc->descr.next); - barrier(); - np->prev_rx_desc->descr.eol = 0; - flush_dma_descr(&np->prev_rx_desc->descr, 0); // Workaround cache bug - np->prev_rx_desc = - phys_to_virt((int)np->prev_rx_desc->descr.next); - flush_dma_descr(&np->prev_rx_desc->descr, 1); // Workaround cache bug - } else { - np->new_rx_package = 0; + np->new_rx_package = 1; + crisv32_eth_rx_ring_advance(np); + } + + morework = crisv32_has_rx_work(np, &np->active_rx_desc->descr); + + while (morework && dev->quota) + { + crisv32_eth_receive_packet(dev); + dev->quota--; + np->stats.rx_packets++; + + /* Ack irq and restart rx dma */ + REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr); + DMA_CONTINUE_DATA(np->dma_in_inst); + + morework = crisv32_has_rx_work(np, &np->active_rx_desc->descr); } + update_rx_stats(np); + + /* it's our responsability to update the global budget. */ + *budget -= (workdone - dev->quota); + + if (!morework) { + /* first mark as done, then enable irq's */ + netif_rx_complete(dev); + crisv32_enable_rx_ints(np); + } + + return morework; } /* @@ -1075,7 +1224,8 @@ crisv32_eth_send_packet(struct sk_buff * dev->trans_start = jiffies; spin_lock_irqsave(&np->leds->led_lock, flags); - if (!np->leds->led_active && time_after(jiffies, np->leds->led_next_time)) { + if (!np->leds->led_active && time_after(jiffies, + np->leds->led_next_time)) { /* light the network leds depending on the current speed. */ crisv32_set_network_leds(LED_ACTIVITY, dev); @@ -1116,9 +1266,17 @@ crisv32_eth_send_packet(struct sk_buff * { crisv32_eth_hw_send_packet(buf, skb->len, np); } + /* Stop queue if full. */ - if (np->active_tx_desc == np->catch_tx_desc) + if ( +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + phys_to_virt((int)np->active_tx_desc->descr.next) +#else + np->active_tx_desc +#endif + == np->catch_tx_desc) { netif_stop_queue(dev); + } np->txpackets++; spin_unlock_irqrestore(&np->lock, flags); @@ -1136,7 +1294,8 @@ crisv32_eth_hw_send_packet(unsigned char /* Configure the tx dma descriptor. */ #ifdef CONFIG_CRIS_MACH_ARTPEC3 if (np->gigabit_mode) { - np->active_tx_desc->descr.buf = (unsigned char *) crisv32_intmem_virt_to_phys(buf); + np->active_tx_desc->descr.buf = + (unsigned char *) crisv32_intmem_virt_to_phys(buf); } else #endif { @@ -1185,14 +1344,14 @@ static void crisv32_eth_tx_timeout(struct net_device *dev) { struct crisv32_ethernet_local *np = netdev_priv(dev); - reg_dma_rw_cfg cfg = {0}; reg_dma_rw_stat stat = {0}; unsigned long flags; printk(KERN_WARNING "%s: transmit timed out\n", dev->name); - spin_lock_irqsave(&np->lock, flags); + update_tx_stats(np); + crisv32_ethernet_bug(dev); np->txpackets = 0; @@ -1200,9 +1359,7 @@ crisv32_eth_tx_timeout(struct net_device np->stats.tx_errors++; /* Reset the TX DMA in case it has hung on something. */ - cfg.en = 0; - REG_WR(dma, np->dma_out_inst, rw_cfg, cfg); - + DMA_RESET(np->dma_out_inst); do { stat = REG_RD(dma, np->dma_out_inst, rw_stat); } while (stat.mode != regk_dma_rst); @@ -1220,12 +1377,26 @@ crisv32_eth_tx_timeout(struct net_device phys_to_virt((int)np->catch_tx_desc->descr.next); } while (np->catch_tx_desc != np->active_tx_desc); + reg_eth_rw_gen_ctrl gen_ctrl = { 0 }; + gen_ctrl.en = regk_eth_yes; + REG_WR(eth, np->eth_inst, rw_gen_ctrl, gen_ctrl); + + int ack_intr = 0xffff; + REG_WR_INT(eth, np->eth_inst, rw_ack_intr, ack_intr); + reg_eth_rw_clr_err clr_err; + clr_err.clr = 1; + REG_WR(eth, np->eth_inst, rw_clr_err, clr_err); + + crisv32_enable_tx_ints(np); + + DMA_ENABLE(np->dma_out_inst); +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + DMA_WR_CMD(np->dma_out_inst, regk_dma_set_w_size4); +#endif + + /* Next packet will restart output DMA. */ + np->sender_started = 0; - /* Start output DMA. */ - REG_WR(dma, np->dma_out_inst, rw_group_down, - (int) virt_to_phys(&np->ctxt_out)); - DMA_WR_CMD(np->dma_out_inst, regk_dma_load_c); - DMA_WR_CMD(np->dma_out_inst, regk_dma_load_d | regk_dma_burst); spin_unlock_irqrestore(&np->lock, flags); /* Tell the upper layers we're ok again. */ @@ -1453,7 +1624,7 @@ static void crisv32_eth_get_drvinfo(stru struct ethtool_drvinfo *info) { strncpy(info->driver, "ETRAX FS", sizeof(info->driver) - 1); - strncpy(info->version, "$Revision: 1.96 $", sizeof(info->version) - 1); + strncpy(info->version, "$Revision: 1.96.2.1 $", sizeof(info->version) - 1); strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1); strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1); } @@ -1559,10 +1730,12 @@ crisv32_eth_switch_intmem_usage(struct n /* Setup the list entry */ np->tx_intmem_buf_list[i].free = 1; np->tx_intmem_buf_list[i].buf = intmem_tmp; - np->tx_intmem_buf_list[i].next = &np->tx_intmem_buf_list[i + 1]; + np->tx_intmem_buf_list[i].next = + &np->tx_intmem_buf_list[i + 1]; } /* Setup the last list entry */ - np->tx_intmem_buf_list[NBR_INTMEM_TX_BUF - 1].next = &np->tx_intmem_buf_list[0]; + np->tx_intmem_buf_list[NBR_INTMEM_TX_BUF - 1].next = + &np->tx_intmem_buf_list[0]; /* Setup initial pointer */ np->intmem_tx_buf_active = np->tx_intmem_buf_list; np->intmem_tx_buf_catch = np->tx_intmem_buf_list; @@ -1571,7 +1744,8 @@ crisv32_eth_switch_intmem_usage(struct n for (i=0; i < NBR_INTMEM_RX_DESC; i++) { /* Allocate internal memory */ intmem_tmp = NULL; - intmem_tmp = crisv32_intmem_alloc(MAX_MEDIA_DATA_SIZE, 32); + intmem_tmp = crisv32_intmem_alloc(MAX_MEDIA_DATA_SIZE, + 32); /* Check that we really got the memory */ if (intmem_tmp == NULL) { printk(KERN_ERR "%s: Can't allocate intmem for" @@ -1595,7 +1769,8 @@ crisv32_eth_switch_intmem_usage(struct n (void*) virt_to_phys(&np->dma_rx_descr_list[0].descr); /* Initialise initial receive pointers. */ np->active_rx_desc = &np->dma_rx_descr_list[0]; - np->prev_rx_desc = &np->dma_rx_descr_list[NBR_INTMEM_RX_DESC - 1]; + np->prev_rx_desc = + &np->dma_rx_descr_list[NBR_INTMEM_RX_DESC - 1]; np->last_rx_desc = np->prev_rx_desc; np->gigabit_mode = 1; @@ -1655,6 +1830,10 @@ crisv32_eth_switch_intmem_usage(struct n DMA_WR_CMD(np->dma_in_inst, regk_dma_load_c); DMA_WR_CMD(np->dma_in_inst, regk_dma_load_d | regk_dma_burst); +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + /* Reset the dma word size. */ + DMA_WR_CMD(np->dma_in_inst, regk_dma_set_w_size2); +#endif netif_wake_queue(dev); @@ -1983,6 +2162,34 @@ national_check_duplex(struct net_device } static void +vitesse_check_speed(struct net_device *dev) +{ + unsigned long data; + struct crisv32_ethernet_local *np = netdev_priv(dev); + + data = crisv32_eth_get_mdio_reg(dev, MDIO_VIT_AUX_STAT); + if ((data & 0x18) == MDIO_VIT_1000) + np->current_speed = 1000; + else if ((data & 0x18) == MDIO_VIT_100) + np->current_speed = 100; + else + np->current_speed = 10; +} + +static void +vitesse_check_duplex(struct net_device *dev) +{ + unsigned long data; + struct crisv32_ethernet_local *np = netdev_priv(dev); + + data = crisv32_eth_get_mdio_reg(dev, MDIO_VIT_AUX_STAT); + if (data & 0x20) + np->full_duplex = 1; + else + np->full_duplex = 0; +} + +static void crisv32_eth_reset_tranceiver(struct net_device *dev) { int i; @@ -2120,7 +2327,8 @@ crisv32_clear_network_leds(unsigned long unsigned long flags; spin_lock_irqsave(&np->leds->led_lock, flags); - if (np->leds->led_active && time_after(jiffies, np->leds->led_next_time)) { + if (np->leds->led_active && time_after(jiffies, + np->leds->led_next_time)) { crisv32_set_network_leds(LED_NOACTIVITY, dev); /* Set the earliest time we may set the LED */ @@ -2169,7 +2377,8 @@ crisv32_set_network_leds(int active, str } if (!np->current_speed) { - /* Set link down if none of the interfaces that use this led group is up */ + /* Set link down if none of the interfaces that use this led + group is up */ if ((np->leds->ifisup[0] + np->leds->ifisup[1]) == 0) { #if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION) /* Make LED red, link is down */ @@ -2195,7 +2404,7 @@ crisv32_set_network_leds(int active, str static void crisv32_netpoll(struct net_device* netdev) { - crisv32rx_eth_interrupt(DMA0_INTR_VECT, netdev, NULL); + crisv32rx_eth_interrupt(DMA0_INTR_VECT, netdev); } #endif @@ -2239,20 +2448,29 @@ static void crisv32_ethernet_bug(struct /* Get the current output dma position. */ stat = REG_RD(dma, np->dma_out_inst, rw_stat); - dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_out_inst, rw_data)); + +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + if (np->gigabit_mode) { + dma_pos = crisv32_intmem_phys_to_virt( + REG_RD_INT(dma, np->dma_out_inst, rw_data)); + in_dma_pos = crisv32_intmem_phys_to_virt( + REG_RD_INT(dma, np->dma_in_inst, rw_data)); + } else +#endif + { + dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_out_inst, + rw_data)); + in_dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_in_inst, + rw_data)); + } in_stat = REG_RD(dma, np->dma_in_inst, rw_stat); - in_dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_in_inst, rw_data)); printk("%s:\n" "stat.list_state=%x\n" "stat.mode=%x\n" "stat.stream_cmd_src=%x\n" "dma_pos=%x\n" - "in_stat.list_state=%x\n" - "in_stat.mode=%x\n" - "in_stat.stream_cmd_src=%x\n" - "in_dma_pos=%x\n" - "catch=%x active=%x\n" + "tx catch=%x active=%x\n" "packets=%d queue=%d\n" "intr_vect.r_vect=%x\n" "dma.r_masked_intr=%x dma.rw_ack_intr=%x " @@ -2261,8 +2479,6 @@ static void crisv32_ethernet_bug(struct __func__, stat.list_state, stat.mode, stat.stream_cmd_src, (unsigned int)dma_pos, - in_stat.list_state, in_stat.mode, in_stat.stream_cmd_src, - (unsigned int)in_dma_pos, (unsigned int)&np->catch_tx_desc->descr, (unsigned int)&np->active_tx_desc->descr, np->txpackets, @@ -2274,6 +2490,39 @@ static void crisv32_ethernet_bug(struct REG_RD_INT(dma, np->dma_out_inst, rw_intr_mask), REG_RD_INT(eth, np->eth_inst, r_stat)); + printk("in_stat.list_state=%x\n" + "in_stat.mode=%x\n" + "in_stat.stream_cmd_src=%x\n" + "in_dma_pos=%x\n" + "rx last=%x prev=%x active=%x\n", + in_stat.list_state, in_stat.mode, in_stat.stream_cmd_src, + (unsigned int)in_dma_pos, + (unsigned int)&np->last_rx_desc->descr, + (unsigned int)&np->prev_rx_desc->descr, + (unsigned int)&np->active_rx_desc->descr); + + + printk("rx-descriptors:\n"); + for (i = 0; i < NBR_RX_DESC; i++) { + printk("rxdesc[%d]=0x%x\n", i, (unsigned int) + virt_to_phys(&np->dma_rx_descr_list[i].descr)); + printk("rxdesc[%d].skb=0x%x\n", i, + (unsigned int)np->dma_rx_descr_list[i].skb); + printk("rxdesc[%d].buf=0x%x\n", i, + (unsigned int)np->dma_rx_descr_list[i].descr.buf); + printk("rxdesc[%d].after=0x%x\n", i, + (unsigned int)np->dma_rx_descr_list[i].descr.after); + printk("rxdesc[%d].intr=%x\n", i, + np->dma_rx_descr_list[i].descr.intr); + printk("rxdesc[%d].eol=%x\n", i, + np->dma_rx_descr_list[i].descr.eol); + printk("rxdesc[%d].out_eop=%x\n", i, + np->dma_rx_descr_list[i].descr.out_eop); + printk("rxdesc[%d].in_eop=%x\n", i, + np->dma_rx_descr_list[i].descr.in_eop); + printk("rxdesc[%d].wait=%x\n", i, + np->dma_rx_descr_list[i].descr.wait); + } printk("tx-descriptors:\n"); for (i = 0; i < NBR_TX_DESC; i++) { printk("txdesc[%d]=0x%x\n", i, (unsigned int) @@ -2290,6 +2539,8 @@ static void crisv32_ethernet_bug(struct np->dma_tx_descr_list[i].descr.eol); printk("txdesc[%d].out_eop=%x\n", i, np->dma_tx_descr_list[i].descr.out_eop); + printk("txdesc[%d].in_eop=%x\n", i, + np->dma_tx_descr_list[i].descr.in_eop); printk("txdesc[%d].wait=%x\n", i, np->dma_tx_descr_list[i].descr.wait); } @@ -2302,4 +2553,26 @@ crisv32_init_module(void) return crisv32_ethernet_init(); } +static int __init +crisv32_boot_setup(char* str) +{ + struct sockaddr sa = {0}; + int i; + + /* Parse the colon separated Ethernet station address */ + for (i = 0; i < ETH_ALEN; i++) { + unsigned int tmp; + if (sscanf(str + 3*i, "%2x", &tmp) != 1) { + printk(KERN_WARNING "Malformed station address"); + return 0; + } + sa.sa_data[i] = (char)tmp; + } + + default_mac_iface0 = sa; + return 1; +} + +__setup("crisv32_eth=", crisv32_boot_setup); + module_init(crisv32_init_module); Index: os/linux-2.6/drivers/net/cris/eth_v32.h =================================================================== RCS file: /usr/local/cvs/linux/os/linux-2.6/drivers/net/cris/eth_v32.h,v retrieving revision 1.28 retrieving revision 1.28.2.1 diff -b -u -p -r1.28 -r1.28.2.1 --- os/linux-2.6/drivers/net/cris/eth_v32.h 6 Feb 2007 10:10:37 -0000 1.28 +++ os/linux-2.6/drivers/net/cris/eth_v32.h 4 Sep 2007 11:19:32 -0000 1.28.2.1 @@ -12,10 +12,10 @@ #define MAX_MEDIA_DATA_SIZE 1522 /* Max packet size. */ -#define NBR_RX_DESC 64 /* Number of RX descriptors. */ +#define NBR_RX_DESC 16 /* Number of RX descriptors. */ #define NBR_TX_DESC 16 /* Number of TX descriptors. */ #ifdef CONFIG_CRIS_MACH_ARTPEC3 -#define NBR_INTMEM_RX_DESC 5 /* Number of RX descriptors in int. mem. +#define NBR_INTMEM_RX_DESC 16 /* Number of RX descriptors in int. mem. * when running in gigabit mode. * Should be less then NBR_RX_DESC */ @@ -62,6 +62,13 @@ #define MDIO_NAT_100 (0x0001 << 3) #define MDIO_NAT_FULL_DUPLEX_IND (0x0001 << 1) +/* Vitesse VCS8641 specific */ +#define MDIO_VIT_AUX_STAT 0x1c +#define MDIO_VIT_1000 (0x2 << 3) +#define MDIO_VIT_100 (0x1 << 3) +#define MDIO_VIT_10 0 +#define MDIO_VIT_FD (0x1 << 5) + /* Network flash constants */ #define NET_FLASH_TIME (HZ/50) /* 20 ms */ #define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ @@ -171,7 +178,7 @@ struct crisv32_ethernet_local { unsigned int mdio_phy_addr; struct transceiver_ops *transceiver; - + unsigned long newbuf; /* * TX control lock. This protects the transmit buffer ring state along * with the "tx full" state of the driver. This means all netif_queue @@ -185,6 +192,7 @@ struct crisv32_ethernet_local { static int crisv32_ethernet_init(void); static int crisv32_ethernet_device_init(struct net_device* dev); static int crisv32_eth_open(struct net_device *dev); +static int crisv32_eth_poll(struct net_device *dev, int *budget); static int crisv32_eth_close(struct net_device *dev); static int crisv32_eth_set_mac_address(struct net_device *dev, void *vpntr); static irqreturn_t crisv32rx_eth_interrupt(int irq, void *dev_id); @@ -221,6 +229,8 @@ static void intel_check_speed(struct net static void intel_check_duplex(struct net_device *dev); static void national_check_speed(struct net_device* dev); static void national_check_duplex(struct net_device *dev); +static void vitesse_check_speed(struct net_device* dev); +static void vitesse_check_duplex(struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER static void crisv32_netpoll(struct net_device* dev);
Save the patch in a file, e.g. eth_patch. Apply the patch from the root of your tree:
patch -p 0 < eth_patch
rebuild the kernel:
make -C packages/os/linux-2.6 install
and build a new image:
make images
— Jesper Bengtsson 2007/09/10 09:27