Newer
Older
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
#include <linux/prefetch.h>
MODULE_VERSION(DRV_VER);
MODULE_DEVICE_TABLE(pci, be_dev_ids);
MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
MODULE_AUTHOR("ServerEngines Corporation");
MODULE_LICENSE("GPL");
static ushort rx_frag_size = 2048;
module_param(rx_frag_size, ushort, S_IRUGO);
module_param(num_vfs, uint, S_IRUGO);
MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize");
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)},
{ 0 }
};
MODULE_DEVICE_TABLE(pci, be_dev_ids);
static const char * const ue_status_low_desc[] = {
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"CEV",
"CTX",
"DBUF",
"ERX",
"Host",
"MPU",
"NDMA",
"PTC ",
"RDMA ",
"RXF ",
"RXIPS ",
"RXULP0 ",
"RXULP1 ",
"RXULP2 ",
"TIM ",
"TPOST ",
"TPRE ",
"TXIPS ",
"TXULP0 ",
"TXULP1 ",
"UC ",
"WDMA ",
"TXULP2 ",
"HOST1 ",
"P0_OB_LINK ",
"P1_OB_LINK ",
"HOST_GPIO ",
"MBOX ",
"AXGMAC0",
"AXGMAC1",
"JTAG",
"MPU_INTPEND"
};
/* UE Status High CSR */
static const char * const ue_status_hi_desc[] = {
"LPCMEMHOST",
"MGMT_MAC",
"PCS0ONLINE",
"MPU_IRAM",
"PCS1ONLINE",
"PCTL0",
"PCTL1",
"PMEM",
"RR",
"TXPB",
"RXPP",
"XAUI",
"TXP",
"ARM",
"IPC",
"HOST2",
"HOST3",
"HOST4",
"HOST5",
"HOST6",
"HOST7",
"HOST8",
"HOST9",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
if (mem->va)
dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va,
mem->dma);
}
static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
u16 len, u16 entry_size)
{
struct be_dma_mem *mem = &q->dma_mem;
memset(q, 0, sizeof(*q));
q->len = len;
q->entry_size = entry_size;
mem->size = len * entry_size;
mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma,
GFP_KERNEL);
if (!mem->va)
return -1;
memset(mem->va, 0, mem->size);
return 0;
}
static void be_intr_set(struct be_adapter *adapter, bool enable)
u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
u32 reg = ioread32(addr);
u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
if (adapter->eeh_err)
return;
if (!enabled && enable)
else if (enabled && !enable)
static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
{
u32 val = 0;
val |= qid & DB_RQ_RING_ID_MASK;
val |= posted << DB_RQ_NUM_POSTED_SHIFT;
iowrite32(val, adapter->db + DB_RQ_OFFSET);
static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
{
u32 val = 0;
val |= qid & DB_TXULP_RING_ID_MASK;
val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
static void be_eq_notify(struct be_adapter *adapter, u16 qid,
bool arm, bool clear_int, u16 num_popped)
{
u32 val = 0;
val |= qid & DB_EQ_RING_ID_MASK;
val |= ((qid & DB_EQ_RING_ID_EXT_MASK) <<
DB_EQ_RING_ID_EXT_MASK_SHIFT);
if (adapter->eeh_err)
return;
if (arm)
val |= 1 << DB_EQ_REARM_SHIFT;
if (clear_int)
val |= 1 << DB_EQ_CLR_SHIFT;
val |= 1 << DB_EQ_EVNT_SHIFT;
val |= num_popped << DB_EQ_NUM_POPPED_SHIFT;
iowrite32(val, adapter->db + DB_EQ_OFFSET);
void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
{
u32 val = 0;
val |= qid & DB_CQ_RING_ID_MASK;
val |= ((qid & DB_CQ_RING_ID_EXT_MASK) <<
DB_CQ_RING_ID_EXT_MASK_SHIFT);
if (adapter->eeh_err)
return;
if (arm)
val |= 1 << DB_CQ_REARM_SHIFT;
val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
iowrite32(val, adapter->db + DB_CQ_OFFSET);
}
static int be_mac_addr_set(struct net_device *netdev, void *p)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
int status = 0;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
/* MAC addr configuration will be done in hardware for VFs
* by their corresponding PFs. Just copy to netdev addr here
*/
if (!be_physfn(adapter))
goto netdev_addr;
status = be_cmd_pmac_del(adapter, adapter->if_handle,
adapter->pmac_id, 0);
if (status)
return status;
status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
adapter->if_handle, &adapter->pmac_id, 0);
if (!status)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
return status;
}
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
static void populate_be2_stats(struct be_adapter *adapter)
{
struct be_drv_stats *drvs = &adapter->drv_stats;
struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
struct be_port_rxf_stats_v0 *port_stats =
be_port_rxf_stats_from_cmd(adapter);
struct be_rxf_stats_v0 *rxf_stats =
be_rxf_stats_from_cmd(adapter);
drvs->rx_pause_frames = port_stats->rx_pause_frames;
drvs->rx_crc_errors = port_stats->rx_crc_errors;
drvs->rx_control_frames = port_stats->rx_control_frames;
drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow;
drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
drvs->rx_input_fifo_overflow_drop =
port_stats->rx_input_fifo_overflow;
drvs->rx_dropped_header_too_small =
port_stats->rx_dropped_header_too_small;
drvs->rx_address_match_errors =
port_stats->rx_address_match_errors;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
drvs->tx_pauseframes = port_stats->tx_pauseframes;
drvs->tx_controlframes = port_stats->tx_controlframes;
if (adapter->port_num)
drvs->jabber_events =
rxf_stats->port1_jabber_events;
else
drvs->jabber_events =
rxf_stats->port0_jabber_events;
drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
drvs->forwarded_packets = rxf_stats->forwarded_packets;
drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
drvs->rx_drops_no_tpre_descr =
rxf_stats->rx_drops_no_tpre_descr;
drvs->rx_drops_too_many_frags =
rxf_stats->rx_drops_too_many_frags;
adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
}
static void populate_be3_stats(struct be_adapter *adapter)
{
struct be_drv_stats *drvs = &adapter->drv_stats;
struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
struct be_rxf_stats_v1 *rxf_stats =
be_rxf_stats_from_cmd(adapter);
struct be_port_rxf_stats_v1 *port_stats =
be_port_rxf_stats_from_cmd(adapter);
drvs->rx_priority_pause_frames = 0;
drvs->pmem_fifo_overflow_drop = 0;
drvs->rx_pause_frames = port_stats->rx_pause_frames;
drvs->rx_crc_errors = port_stats->rx_crc_errors;
drvs->rx_control_frames = port_stats->rx_control_frames;
drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
drvs->rx_dropped_header_too_small =
port_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop =
port_stats->rx_input_fifo_overflow_drop;
drvs->rx_address_match_errors =
port_stats->rx_address_match_errors;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
drvs->rxpp_fifo_overflow_drop =
port_stats->rxpp_fifo_overflow_drop;
drvs->tx_pauseframes = port_stats->tx_pauseframes;
drvs->tx_controlframes = port_stats->tx_controlframes;
drvs->jabber_events = port_stats->jabber_events;
drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
drvs->forwarded_packets = rxf_stats->forwarded_packets;
drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
drvs->rx_drops_no_tpre_descr =
rxf_stats->rx_drops_no_tpre_descr;
drvs->rx_drops_too_many_frags =
rxf_stats->rx_drops_too_many_frags;
adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
}
static void populate_lancer_stats(struct be_adapter *adapter)
{
struct be_drv_stats *drvs = &adapter->drv_stats;
struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd
(adapter);
drvs->rx_priority_pause_frames = 0;
drvs->pmem_fifo_overflow_drop = 0;
drvs->rx_pause_frames =
make_64bit_val(pport_stats->rx_pause_frames_hi,
pport_stats->rx_pause_frames_lo);
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi,
pport_stats->rx_crc_errors_lo);
drvs->rx_control_frames =
make_64bit_val(pport_stats->rx_control_frames_hi,
pport_stats->rx_control_frames_lo);
drvs->rx_in_range_errors = pport_stats->rx_in_range_errors;
drvs->rx_frame_too_long =
make_64bit_val(pport_stats->rx_internal_mac_errors_hi,
pport_stats->rx_frames_too_long_lo);
drvs->rx_dropped_runt = pport_stats->rx_dropped_runt;
drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors;
drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors;
drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors;
drvs->rx_dropped_tcp_length =
pport_stats->rx_dropped_invalid_tcp_length;
drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small;
drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short;
drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors;
drvs->rx_dropped_header_too_small =
pport_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
drvs->rx_address_match_errors = pport_stats->rx_address_match_errors;
drvs->rx_alignment_symbol_errors =
make_64bit_val(pport_stats->rx_symbol_errors_hi,
pport_stats->rx_symbol_errors_lo);
drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi,
pport_stats->tx_pause_frames_lo);
drvs->tx_controlframes =
make_64bit_val(pport_stats->tx_control_frames_hi,
pport_stats->tx_control_frames_lo);
drvs->jabber_events = pport_stats->rx_jabbers;
drvs->rx_drops_no_pbuf = 0;
drvs->rx_drops_no_txpb = 0;
drvs->rx_drops_no_erx_descr = 0;
drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue;
drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi,
pport_stats->num_forwards_lo);
drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi,
pport_stats->rx_drops_mtu_lo);
drvs->rx_drops_no_tpre_descr = 0;
drvs->rx_drops_too_many_frags =
make_64bit_val(pport_stats->rx_drops_too_many_frags_hi,
pport_stats->rx_drops_too_many_frags_lo);
}
void be_parse_stats(struct be_adapter *adapter)
{
if (adapter->generation == BE_GEN3) {
if (lancer_chip(adapter))
populate_lancer_stats(adapter);
else
populate_be3_stats(adapter);
} else {
populate_be2_stats(adapter);
void netdev_stats_update(struct be_adapter *adapter)
struct be_drv_stats *drvs = &adapter->drv_stats;
struct net_device_stats *dev_stats = &adapter->netdev->stats;
unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0;
for_all_rx_queues(adapter, rxo, i) {
pkts += rx_stats(rxo)->rx_pkts;
bytes += rx_stats(rxo)->rx_bytes;
mcast += rx_stats(rxo)->rx_mcast_pkts;
drops += rx_stats(rxo)->rx_dropped;
/* no space in linux buffers: best possible approximation */
if (adapter->generation == BE_GEN3) {
be_erx_stats_from_cmd(adapter);
drops += erx->rx_drops_no_fragments[rxo->q.id];
be_erx_stats_from_cmd(adapter);
drops += erx->rx_drops_no_fragments[rxo->q.id];
dev_stats->rx_packets = pkts;
dev_stats->rx_bytes = bytes;
dev_stats->multicast = mcast;
dev_stats->rx_dropped = drops;
pkts += tx_stats(txo)->be_tx_pkts;
bytes += tx_stats(txo)->be_tx_bytes;
dev_stats->tx_packets = pkts;
dev_stats->tx_bytes = bytes;
dev_stats->rx_errors = drvs->rx_crc_errors +
drvs->rx_alignment_symbol_errors +
drvs->rx_in_range_errors +
drvs->rx_out_range_errors +
drvs->rx_frame_too_long +
drvs->rx_dropped_too_small +
drvs->rx_dropped_too_short +
drvs->rx_dropped_header_too_small +
drvs->rx_dropped_tcp_length +
drvs->rx_dropped_runt +
drvs->rx_tcp_checksum_errs +
drvs->rx_ip_checksum_errs +
drvs->rx_udp_checksum_errs;
dev_stats->rx_length_errors = drvs->rx_in_range_errors +
drvs->rx_out_range_errors +
drvs->rx_frame_too_long;
dev_stats->rx_crc_errors = drvs->rx_crc_errors;
dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
/* receiver fifo overrun */
/* drops_no_pbuf is no per i/f, it's per BE card */
dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
drvs->rx_input_fifo_overflow_drop +
drvs->rx_drops_no_pbuf;
void be_link_status_update(struct be_adapter *adapter, bool link_up)
{
struct net_device *netdev = adapter->netdev;
/* If link came up or went down */
if (adapter->link_up != link_up) {
adapter->link_speed = -1;
if (link_up) {
netif_carrier_on(netdev);
printk(KERN_INFO "%s: Link up\n", netdev->name);
} else {
netif_carrier_off(netdev);
printk(KERN_INFO "%s: Link down\n", netdev->name);
adapter->link_up = link_up;
}
}
/* Update the EQ delay n BE based on the RX frags consumed / sec */
static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
struct be_eq_obj *rx_eq = &rxo->rx_eq;
struct be_rx_stats *stats = &rxo->stats;
ulong now = jiffies;
u32 eqd;
if (!rx_eq->enable_aic)
return;
/* Wrapped around */
if (time_before(now, stats->rx_fps_jiffies)) {
stats->rx_fps_jiffies = now;
return;
}
if ((now - stats->rx_fps_jiffies) < HZ)
stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) /
((now - stats->rx_fps_jiffies) / HZ);
stats->prev_rx_frags = stats->rx_frags;
eqd = stats->rx_fps / 110000;
eqd = eqd << 3;
if (eqd > rx_eq->max_eqd)
eqd = rx_eq->max_eqd;
if (eqd < rx_eq->min_eqd)
eqd = rx_eq->min_eqd;
if (eqd < 10)
eqd = 0;
if (eqd != rx_eq->cur_eqd)
be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd);
static u32 be_calc_rate(u64 bytes, unsigned long ticks)
{
u64 rate = bytes;
do_div(rate, ticks / HZ);
rate <<= 3; /* bytes/sec -> bits/sec */
do_div(rate, 1000000ul); /* MB/Sec */
return rate;
}
static void be_tx_rate_update(struct be_tx_obj *txo)
struct be_tx_stats *stats = tx_stats(txo);
ulong now = jiffies;
/* Wrapped around? */
if (time_before(now, stats->be_tx_jiffies)) {
stats->be_tx_jiffies = now;
return;
}
/* Update tx rate once in two seconds */
if ((now - stats->be_tx_jiffies) > 2 * HZ) {
stats->be_tx_rate = be_calc_rate(stats->be_tx_bytes
- stats->be_tx_bytes_prev,
now - stats->be_tx_jiffies);
stats->be_tx_jiffies = now;
stats->be_tx_bytes_prev = stats->be_tx_bytes;
}
}
static void be_tx_stats_update(struct be_tx_obj *txo,
u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped)
struct be_tx_stats *stats = tx_stats(txo);
stats->be_tx_reqs++;
stats->be_tx_wrbs += wrb_cnt;
stats->be_tx_bytes += copied;
stats->be_tx_pkts += (gso_segs ? gso_segs : 1);
if (stopped)
stats->be_tx_stops++;
}
/* Determine number of WRB entries needed to xmit data in an skb */
static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb,
bool *dummy)
int cnt = (skb->len > skb->data_len);
cnt += skb_shinfo(skb)->nr_frags;
if (lancer_chip(adapter) || !(cnt & 1)) {
*dummy = false;
} else {
/* add a dummy to make it an even num */
cnt++;
*dummy = true;
BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT);
return cnt;
}
static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
{
wrb->frag_pa_hi = upper_32_bits(addr);
wrb->frag_pa_lo = addr & 0xFFFFFFFF;
wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
}
static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
struct sk_buff *skb, u32 wrb_cnt, u32 len)
u8 vlan_prio = 0;
u16 vlan_tag = 0;
memset(hdr, 0, sizeof(*hdr));
AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
hdr, skb_shinfo(skb)->gso_size);
if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
if (lancer_chip(adapter) && adapter->sli_family ==
LANCER_A0_SLI_FAMILY) {
AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
if (is_tcp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb,
tcpcs, hdr, 1);
else if (is_udp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb,
udpcs, hdr, 1);
}
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (is_tcp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
else if (is_udp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
}
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
vlan_tag = vlan_tx_tag_get(skb);
vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
/* If vlan priority provided by OS is NOT in available bmap */
if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
adapter->recommended_prio;
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
}
AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
}
static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
bool unmap_single)
{
dma_addr_t dma;
be_dws_le_to_cpu(wrb, sizeof(*wrb));
dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo;
dma_unmap_single(dev, dma, wrb->frag_len,
DMA_TO_DEVICE);
dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE);
static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb)
{
dma_addr_t busaddr;
int i, copied = 0;
struct device *dev = &adapter->pdev->dev;
struct sk_buff *first_skb = skb;
struct be_eth_wrb *wrb;
struct be_eth_hdr_wrb *hdr;
bool map_single = false;
u16 map_head;
hdr = queue_head_node(txq);
queue_head_inc(txq);
if (skb->len > skb->data_len) {
busaddr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, busaddr))
goto dma_err;
map_single = true;
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, len);
be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
copied += len;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[i];
busaddr = dma_map_page(dev, frag->page, frag->page_offset,
frag->size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, busaddr))
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, frag->size);
be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
copied += frag->size;
}
if (dummy_wrb) {
wrb = queue_head_node(txq);
wrb_fill(wrb, 0, 0);
be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
}
wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied);
be_dws_cpu_to_le(hdr, sizeof(*hdr));
return copied;
dma_err:
txq->head = map_head;
while (copied) {
wrb = queue_head_node(txq);
map_single = false;
copied -= wrb->frag_len;
queue_head_inc(txq);
}
return 0;
static netdev_tx_t be_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
struct be_queue_info *txq = &txo->q;
u32 wrb_cnt = 0, copied = 0;
u32 start = txq->head;
bool dummy_wrb, stopped = false;
wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
if (copied) {
/* record the sent skb in the sent_skb table */
BUG_ON(txo->sent_skb_list[start]);
txo->sent_skb_list[start] = skb;
/* Ensure txq has space for the next skb; Else stop the queue
* *BEFORE* ringing the tx doorbell, so that we serialze the
* tx compls of the current transmit which'll wake up the queue
*/
atomic_add(wrb_cnt, &txq->used);
if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >=
txq->len) {
netif_stop_subqueue(netdev, skb_get_queue_mapping(skb));
stopped = true;
}
be_txq_notify(adapter, txq->id, wrb_cnt);
be_tx_stats_update(txo, wrb_cnt, copied,
skb_shinfo(skb)->gso_segs, stopped);
} else {
txq->head = start;
dev_kfree_skb_any(skb);
}
return NETDEV_TX_OK;
}
static int be_change_mtu(struct net_device *netdev, int new_mtu)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (new_mtu < BE_MIN_MTU ||
new_mtu > (BE_MAX_JUMBO_FRAME_SIZE -
(ETH_HLEN + ETH_FCS_LEN))) {
dev_info(&adapter->pdev->dev,
"MTU must be between %d and %d bytes\n",
BE_MIN_MTU,
(BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN)));
return -EINVAL;
}
dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n",
netdev->mtu, new_mtu);
netdev->mtu = new_mtu;
return 0;
}
/*
* A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
* If the user configures more, place BE in vlan promiscuous mode.
static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
{
u16 vtag[BE_NUM_VLANS_SUPPORTED];
u16 ntags = 0, i;
int status = 0;
u32 if_handle;
if (vf) {
if_handle = adapter->vf_cfg[vf_num].vf_if_handle;
vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag);
status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0);
}
if (adapter->vlans_added <= adapter->max_vlans) {
for (i = 0; i < VLAN_N_VID; i++) {
if (adapter->vlan_tag[i]) {
vtag[ntags] = cpu_to_le16(i);
ntags++;
}
}
status = be_cmd_vlan_config(adapter, adapter->if_handle,
vtag, ntags, 1, 0);
status = be_cmd_vlan_config(adapter, adapter->if_handle,
NULL, 0, 1, 1);
}
static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
adapter->vlans_added++;
if (!be_physfn(adapter))
return;
if (adapter->vlans_added <= (adapter->max_vlans + 1))
be_vid_config(adapter, false, 0);
}
static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
adapter->vlans_added--;
if (!be_physfn(adapter))
return;
if (adapter->vlans_added <= adapter->max_vlans)
be_vid_config(adapter, false, 0);
static void be_set_multicast_list(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (netdev->flags & IFF_PROMISC) {
be_cmd_promiscuous_config(adapter, true);
adapter->promiscuous = true;
goto done;
/* BE was previously in promiscuous mode; disable it */
if (adapter->promiscuous) {
adapter->promiscuous = false;
be_cmd_promiscuous_config(adapter, false);
/* Enable multicast promisc if num configured exceeds what we support */
if (netdev->flags & IFF_ALLMULTI ||
netdev_mc_count(netdev) > BE_MAX_MC) {
be_cmd_multicast_set(adapter, adapter->if_handle, NULL,
&adapter->mc_cmd_mem);
be_cmd_multicast_set(adapter, adapter->if_handle, netdev,
done:
return;
static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
{
struct be_adapter *adapter = netdev_priv(netdev);
int status;
if (!adapter->sriov_enabled)
return -EPERM;
if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
return -EINVAL;
if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
status = be_cmd_pmac_del(adapter,
adapter->vf_cfg[vf].vf_if_handle,
adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
status = be_cmd_pmac_add(adapter, mac,
adapter->vf_cfg[vf].vf_if_handle,
&adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
mac, vf);
else
memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
static int be_get_vf_config(struct net_device *netdev, int vf,
struct ifla_vf_info *vi)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (!adapter->sriov_enabled)
return -EPERM;
if (vf >= num_vfs)
return -EINVAL;
vi->vf = vf;
vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate;
vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag;
vi->qos = 0;
memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN);
return 0;
}
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
static int be_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos)
{
struct be_adapter *adapter = netdev_priv(netdev);
int status = 0;
if (!adapter->sriov_enabled)
return -EPERM;
if ((vf >= num_vfs) || (vlan > 4095))
return -EINVAL;
if (vlan) {
adapter->vf_cfg[vf].vf_vlan_tag = vlan;
adapter->vlans_added++;
} else {
adapter->vf_cfg[vf].vf_vlan_tag = 0;
adapter->vlans_added--;
}
status = be_vid_config(adapter, true, vf);
if (status)
dev_info(&adapter->pdev->dev,
"VLAN %d config on VF %d failed\n", vlan, vf);
return status;
}
static int be_set_vf_tx_rate(struct net_device *netdev,
int vf, int rate)
{
struct be_adapter *adapter = netdev_priv(netdev);
int status = 0;
if (!adapter->sriov_enabled)
return -EPERM;
if ((vf >= num_vfs) || (rate < 0))
return -EINVAL;
if (rate > 10000)
rate = 10000;
adapter->vf_cfg[vf].vf_tx_rate = rate;
status = be_cmd_set_qos(adapter, rate / 10, vf + 1);