diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 7f500288f6b..4e2a1628484 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -123,6 +123,7 @@ struct tile_net_comps { /* The transmit wake timer for a given cpu and echannel. */ struct tile_net_tx_wake { + int tx_queue_idx; struct hrtimer timer; struct net_device *dev; }; @@ -573,12 +574,14 @@ static void add_comp(gxio_mpipe_equeue_t *equeue, comps->comp_next++; } -static void tile_net_schedule_tx_wake_timer(struct net_device *dev) +static void tile_net_schedule_tx_wake_timer(struct net_device *dev, + int tx_queue_idx) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = &per_cpu(per_cpu_info, tx_queue_idx); struct tile_net_priv *priv = netdev_priv(dev); + struct tile_net_tx_wake *tx_wake = &info->tx_wake[priv->echannel]; - hrtimer_start(&info->tx_wake[priv->echannel].timer, + hrtimer_start(&tx_wake->timer, ktime_set(0, TX_TIMER_DELAY_USEC * 1000UL), HRTIMER_MODE_REL_PINNED); } @@ -587,7 +590,7 @@ static enum hrtimer_restart tile_net_handle_tx_wake_timer(struct hrtimer *t) { struct tile_net_tx_wake *tx_wake = container_of(t, struct tile_net_tx_wake, timer); - netif_wake_subqueue(tx_wake->dev, smp_processor_id()); + netif_wake_subqueue(tx_wake->dev, tx_wake->tx_queue_idx); return HRTIMER_NORESTART; } @@ -1218,6 +1221,7 @@ static int tile_net_open(struct net_device *dev) hrtimer_init(&tx_wake->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + tx_wake->tx_queue_idx = cpu; tx_wake->timer.function = tile_net_handle_tx_wake_timer; tx_wake->dev = dev; } @@ -1291,6 +1295,7 @@ static inline void *tile_net_frag_buf(skb_frag_t *f) * stop the queue and schedule the tx_wake timer. */ static s64 tile_net_equeue_try_reserve(struct net_device *dev, + int tx_queue_idx, struct tile_net_comps *comps, gxio_mpipe_equeue_t *equeue, int num_edescs) @@ -1313,8 +1318,8 @@ static s64 tile_net_equeue_try_reserve(struct net_device *dev, } /* Still nothing; give up and stop the queue for a short while. */ - netif_stop_subqueue(dev, smp_processor_id()); - tile_net_schedule_tx_wake_timer(dev); + netif_stop_subqueue(dev, tx_queue_idx); + tile_net_schedule_tx_wake_timer(dev, tx_queue_idx); return -1; } @@ -1328,11 +1333,12 @@ static s64 tile_net_equeue_try_reserve(struct net_device *dev, static int tso_count_edescs(struct sk_buff *skb) { struct skb_shared_info *sh = skb_shinfo(skb); - unsigned int data_len = skb->data_len; + unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + unsigned int data_len = skb->data_len + skb->hdr_len - sh_len; unsigned int p_len = sh->gso_size; long f_id = -1; /* id of the current fragment */ - long f_size = -1; /* size of the current fragment */ - long f_used = -1; /* bytes used from the current fragment */ + long f_size = skb->hdr_len; /* size of the current fragment */ + long f_used = sh_len; /* bytes used from the current fragment */ long n; /* size of the current piece of payload */ int num_edescs = 0; int segment; @@ -1377,13 +1383,14 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, struct skb_shared_info *sh = skb_shinfo(skb); struct iphdr *ih; struct tcphdr *th; - unsigned int data_len = skb->data_len; + unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + unsigned int data_len = skb->data_len + skb->hdr_len - sh_len; unsigned char *data = skb->data; - unsigned int ih_off, th_off, sh_len, p_len; + unsigned int ih_off, th_off, p_len; unsigned int isum_seed, tsum_seed, id, seq; long f_id = -1; /* id of the current fragment */ - long f_size = -1; /* size of the current fragment */ - long f_used = -1; /* bytes used from the current fragment */ + long f_size = skb->hdr_len; /* size of the current fragment */ + long f_used = sh_len; /* bytes used from the current fragment */ long n; /* size of the current piece of payload */ int segment; @@ -1392,14 +1399,13 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers, th = tcp_hdr(skb); ih_off = skb_network_offset(skb); th_off = skb_transport_offset(skb); - sh_len = th_off + tcp_hdrlen(skb); p_len = sh->gso_size; /* Set up seed values for IP and TCP csum and initialize id and seq. */ isum_seed = ((0xFFFF - ih->check) + (0xFFFF - ih->tot_len) + (0xFFFF - ih->id)); - tsum_seed = th->check + (0xFFFF ^ htons(skb->len)); + tsum_seed = th->check + (0xFFFF ^ htons(sh_len + data_len)); id = ntohs(ih->id); seq = ntohl(th->seq); @@ -1471,21 +1477,22 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, { struct tile_net_priv *priv = netdev_priv(dev); struct skb_shared_info *sh = skb_shinfo(skb); - unsigned int data_len = skb->data_len; + unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + unsigned int data_len = skb->data_len + skb->hdr_len - sh_len; unsigned int p_len = sh->gso_size; gxio_mpipe_edesc_t edesc_head = { { 0 } }; gxio_mpipe_edesc_t edesc_body = { { 0 } }; long f_id = -1; /* id of the current fragment */ - long f_size = -1; /* size of the current fragment */ - long f_used = -1; /* bytes used from the current fragment */ + long f_size = skb->hdr_len; /* size of the current fragment */ + long f_used = sh_len; /* bytes used from the current fragment */ + void *f_data = skb->data; long n; /* size of the current piece of payload */ unsigned long tx_packets = 0, tx_bytes = 0; - unsigned int csum_start, sh_len; + unsigned int csum_start; int segment; /* Prepare to egress the headers: set up header edesc. */ csum_start = skb_checksum_start_offset(skb); - sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb); edesc_head.csum = 1; edesc_head.csum_start = csum_start; edesc_head.csum_dest = csum_start + skb->csum_offset; @@ -1497,7 +1504,6 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, /* Egress all the edescs. */ for (segment = 0; segment < sh->gso_segs; segment++) { - void *va; unsigned char *buf; unsigned int p_used = 0; @@ -1516,10 +1522,9 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, f_id++; f_size = sh->frags[f_id].size; f_used = 0; + f_data = tile_net_frag_buf(&sh->frags[f_id]); } - va = tile_net_frag_buf(&sh->frags[f_id]) + f_used; - /* Use bytes from the current fragment. */ n = p_len - p_used; if (n > f_size - f_used) @@ -1528,7 +1533,7 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, p_used += n; /* Egress a piece of the payload. */ - edesc_body.va = va_to_tile_io_addr(va); + edesc_body.va = va_to_tile_io_addr(f_data) + f_used; edesc_body.xfer_size = n; edesc_body.bound = !(p_used < p_len); gxio_mpipe_equeue_put_at(equeue, edesc_body, slot); @@ -1580,7 +1585,8 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev) local_irq_save(irqflags); /* Try to acquire a completion entry and an egress slot. */ - slot = tile_net_equeue_try_reserve(dev, comps, equeue, num_edescs); + slot = tile_net_equeue_try_reserve(dev, skb->queue_mapping, comps, + equeue, num_edescs); if (slot < 0) { local_irq_restore(irqflags); return NETDEV_TX_BUSY; @@ -1674,7 +1680,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) local_irq_save(irqflags); /* Try to acquire a completion entry and an egress slot. */ - slot = tile_net_equeue_try_reserve(dev, comps, equeue, num_edescs); + slot = tile_net_equeue_try_reserve(dev, skb->queue_mapping, comps, + equeue, num_edescs); if (slot < 0) { local_irq_restore(irqflags); return NETDEV_TX_BUSY; @@ -1844,7 +1851,7 @@ static void tile_net_dev_init(const char *name, const uint8_t *mac) memcpy(dev->dev_addr, mac, 6); dev->addr_len = 6; } else { - eth_random_addr(dev->dev_addr); + eth_hw_addr_random(dev); } /* Register the network device. */