MODULE_AUTHOR("ServerEngines Corporation");
MODULE_LICENSE("GPL");
-static unsigned int rx_frag_size = 2048;
+static ushort rx_frag_size = 2048;
static unsigned int num_vfs;
-module_param(rx_frag_size, uint, S_IRUGO);
+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");
}
static void be_rx_stats_update(struct be_rx_obj *rxo,
- u32 pktsize, u16 numfrags, u8 pkt_type)
+ struct be_rx_compl_info *rxcp)
{
struct be_rx_stats *stats = &rxo->stats;
stats->rx_compl++;
- stats->rx_frags += numfrags;
- stats->rx_bytes += pktsize;
+ stats->rx_frags += rxcp->num_rcvd;
+ stats->rx_bytes += rxcp->pkt_size;
stats->rx_pkts++;
- if (pkt_type == BE_MULTICAST_PACKET)
+ if (rxcp->pkt_type == BE_MULTICAST_PACKET)
stats->rx_mcast_pkts++;
+ if (rxcp->err)
+ stats->rxcp_err++;
}
-static inline bool csum_passed(struct be_eth_rx_compl *rxcp)
+static inline bool csum_passed(struct be_rx_compl_info *rxcp)
{
- u8 l4_cksm, ipv6, ipcksm, tcpf, udpf;
-
- l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp);
- ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp);
- ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp);
- tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
- udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp);
-
/* L4 checksum is not reliable for non TCP/UDP packets.
* Also ignore ipcksm for ipv6 pkts */
- return (tcpf || udpf) && l4_cksm && (ipcksm || ipv6);
+ return (rxcp->tcpf || rxcp->udpf) && rxcp->l4_csum &&
+ (rxcp->ip_csum || rxcp->ipv6);
}
static struct be_rx_page_info *
/* Throwaway the data in the Rx completion */
static void be_rx_compl_discard(struct be_adapter *adapter,
struct be_rx_obj *rxo,
- struct be_eth_rx_compl *rxcp)
+ struct be_rx_compl_info *rxcp)
{
struct be_queue_info *rxq = &rxo->q;
struct be_rx_page_info *page_info;
- u16 rxq_idx, i, num_rcvd;
-
- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+ u16 i, num_rcvd = rxcp->num_rcvd;
for (i = 0; i < num_rcvd; i++) {
- page_info = get_rx_page_info(adapter, rxo, rxq_idx);
+ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
put_page(page_info->page);
memset(page_info, 0, sizeof(*page_info));
- index_inc(&rxq_idx, rxq->len);
+ index_inc(&rxcp->rxq_idx, rxq->len);
}
}
* indicated by rxcp.
*/
static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
- struct sk_buff *skb, struct be_eth_rx_compl *rxcp,
- u16 num_rcvd)
+ struct sk_buff *skb, struct be_rx_compl_info *rxcp)
{
struct be_queue_info *rxq = &rxo->q;
struct be_rx_page_info *page_info;
- u16 rxq_idx, i, j;
- u32 pktsize, hdr_len, curr_frag_len, size;
+ u16 i, j;
+ u16 hdr_len, curr_frag_len, remaining;
u8 *start;
- u8 pkt_type;
-
- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
- pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
- pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp);
-
- page_info = get_rx_page_info(adapter, rxo, rxq_idx);
+ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
start = page_address(page_info->page) + page_info->page_offset;
prefetch(start);
/* Copy data in the first descriptor of this completion */
- curr_frag_len = min(pktsize, rx_frag_size);
+ curr_frag_len = min(rxcp->pkt_size, rx_frag_size);
/* Copy the header portion into skb_data */
- hdr_len = min((u32)BE_HDR_LEN, curr_frag_len);
+ hdr_len = min(BE_HDR_LEN, curr_frag_len);
memcpy(skb->data, start, hdr_len);
skb->len = curr_frag_len;
if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */
}
page_info->page = NULL;
- if (pktsize <= rx_frag_size) {
- BUG_ON(num_rcvd != 1);
- goto done;
+ if (rxcp->pkt_size <= rx_frag_size) {
+ BUG_ON(rxcp->num_rcvd != 1);
+ return;
}
/* More frags present for this completion */
- size = pktsize;
- for (i = 1, j = 0; i < num_rcvd; i++) {
- size -= curr_frag_len;
- index_inc(&rxq_idx, rxq->len);
- page_info = get_rx_page_info(adapter, rxo, rxq_idx);
-
- curr_frag_len = min(size, rx_frag_size);
+ index_inc(&rxcp->rxq_idx, rxq->len);
+ remaining = rxcp->pkt_size - curr_frag_len;
+ for (i = 1, j = 0; i < rxcp->num_rcvd; i++) {
+ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+ curr_frag_len = min(remaining, rx_frag_size);
/* Coalesce all frags from the same physical page in one slot */
if (page_info->page_offset == 0) {
skb->len += curr_frag_len;
skb->data_len += curr_frag_len;
+ remaining -= curr_frag_len;
+ index_inc(&rxcp->rxq_idx, rxq->len);
page_info->page = NULL;
}
BUG_ON(j > MAX_SKB_FRAGS);
-
-done:
- be_rx_stats_update(rxo, pktsize, num_rcvd, pkt_type);
}
/* Process the RX completion indicated by rxcp when GRO is disabled */
static void be_rx_compl_process(struct be_adapter *adapter,
struct be_rx_obj *rxo,
- struct be_eth_rx_compl *rxcp)
+ struct be_rx_compl_info *rxcp)
{
struct sk_buff *skb;
- u32 vlanf, vid;
- u16 num_rcvd;
- u8 vtm;
-
- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
if (unlikely(!skb)) {
return;
}
- skb_fill_rx_data(adapter, rxo, skb, rxcp, num_rcvd);
+ skb_fill_rx_data(adapter, rxo, skb, rxcp);
if (likely(adapter->rx_csum && csum_passed(rxcp)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->truesize = skb->len + sizeof(struct sk_buff);
skb->protocol = eth_type_trans(skb, adapter->netdev);
- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
-
- /* vlanf could be wrongly set in some cards.
- * ignore if vtm is not set */
- if ((adapter->function_mode & 0x400) && !vtm)
- vlanf = 0;
-
- if ((adapter->pvid == vlanf) && !adapter->vlan_tag[vlanf])
- vlanf = 0;
-
- if (unlikely(vlanf)) {
+ if (unlikely(rxcp->vlanf)) {
if (!adapter->vlan_grp || adapter->vlans_added == 0) {
kfree_skb(skb);
return;
}
- vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
- if (!lancer_chip(adapter))
- vid = swab16(vid);
- vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
+ vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid);
} else {
netif_receive_skb(skb);
}
/* Process the RX completion indicated by rxcp when GRO is enabled */
static void be_rx_compl_process_gro(struct be_adapter *adapter,
struct be_rx_obj *rxo,
- struct be_eth_rx_compl *rxcp)
+ struct be_rx_compl_info *rxcp)
{
struct be_rx_page_info *page_info;
struct sk_buff *skb = NULL;
struct be_queue_info *rxq = &rxo->q;
struct be_eq_obj *eq_obj = &rxo->rx_eq;
- u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
- u16 i, rxq_idx = 0, vid, j;
- u8 vtm;
- u8 pkt_type;
-
- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
- pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
- pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp);
-
- /* vlanf could be wrongly set in some cards.
- * ignore if vtm is not set */
- if ((adapter->function_mode & 0x400) && !vtm)
- vlanf = 0;
-
- if ((adapter->pvid == vlanf) && !adapter->vlan_tag[vlanf])
- vlanf = 0;
+ u16 remaining, curr_frag_len;
+ u16 i, j;
skb = napi_get_frags(&eq_obj->napi);
if (!skb) {
return;
}
- remaining = pkt_size;
- for (i = 0, j = -1; i < num_rcvd; i++) {
- page_info = get_rx_page_info(adapter, rxo, rxq_idx);
+ remaining = rxcp->pkt_size;
+ for (i = 0, j = -1; i < rxcp->num_rcvd; i++) {
+ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
curr_frag_len = min(remaining, rx_frag_size);
skb_shinfo(skb)->frags[j].size += curr_frag_len;
remaining -= curr_frag_len;
- index_inc(&rxq_idx, rxq->len);
+ index_inc(&rxcp->rxq_idx, rxq->len);
memset(page_info, 0, sizeof(*page_info));
}
BUG_ON(j > MAX_SKB_FRAGS);
skb_shinfo(skb)->nr_frags = j + 1;
- skb->len = pkt_size;
- skb->data_len = pkt_size;
- skb->truesize += pkt_size;
+ skb->len = rxcp->pkt_size;
+ skb->data_len = rxcp->pkt_size;
+ skb->truesize += rxcp->pkt_size;
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (likely(!vlanf)) {
+ if (likely(!rxcp->vlanf))
napi_gro_frags(&eq_obj->napi);
- } else {
- vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
- if (!lancer_chip(adapter))
- vid = swab16(vid);
+ else
+ vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid);
+}
+
+static void be_parse_rx_compl_v1(struct be_adapter *adapter,
+ struct be_eth_rx_compl *compl,
+ struct be_rx_compl_info *rxcp)
+{
+ rxcp->pkt_size =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl);
+ rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtp, compl);
+ rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, err, compl);
+ rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tcpf, compl);
+ rxcp->ip_csum =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ipcksm, compl);
+ rxcp->l4_csum =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl);
+ rxcp->ipv6 =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl);
+ rxcp->rxq_idx =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, fragndx, compl);
+ rxcp->num_rcvd =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
+ rxcp->pkt_type =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
+ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl);
+ rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl);
+}
+
+static void be_parse_rx_compl_v0(struct be_adapter *adapter,
+ struct be_eth_rx_compl *compl,
+ struct be_rx_compl_info *rxcp)
+{
+ rxcp->pkt_size =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl);
+ rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtp, compl);
+ rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, err, compl);
+ rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, tcpf, compl);
+ rxcp->ip_csum =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ipcksm, compl);
+ rxcp->l4_csum =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl);
+ rxcp->ipv6 =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl);
+ rxcp->rxq_idx =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, fragndx, compl);
+ rxcp->num_rcvd =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
+ rxcp->pkt_type =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
+ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl);
+ rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl);
+}
+
+static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
+{
+ struct be_eth_rx_compl *compl = queue_tail_node(&rxo->cq);
+ struct be_rx_compl_info *rxcp = &rxo->rxcp;
+ struct be_adapter *adapter = rxo->adapter;
- if (!adapter->vlan_grp || adapter->vlans_added == 0)
- return;
+ /* For checking the valid bit it is Ok to use either definition as the
+ * valid bit is at the same position in both v0 and v1 Rx compl */
+ if (compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] == 0)
+ return NULL;
- vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
- }
+ rmb();
+ be_dws_le_to_cpu(compl, sizeof(*compl));
- be_rx_stats_update(rxo, pkt_size, num_rcvd, pkt_type);
-}
+ if (adapter->be3_native)
+ be_parse_rx_compl_v1(adapter, compl, rxcp);
+ else
+ be_parse_rx_compl_v0(adapter, compl, rxcp);
-static struct be_eth_rx_compl *be_rx_compl_get(struct be_rx_obj *rxo)
-{
- struct be_eth_rx_compl *rxcp = queue_tail_node(&rxo->cq);
+ /* vlanf could be wrongly set in some cards. ignore if vtm is not set */
+ if ((adapter->function_mode & 0x400) && !rxcp->vtm)
+ rxcp->vlanf = 0;
- if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
- return NULL;
+ if (!lancer_chip(adapter))
+ rxcp->vid = swab16(rxcp->vid);
- rmb();
- be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
+ if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid])
+ rxcp->vlanf = 0;
+
+ /* As the compl has been parsed, reset it; we wont touch it again */
+ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0;
queue_tail_inc(&rxo->cq);
return rxcp;
}
-/* To reset the valid bit, we need to reset the whole word as
- * when walking the queue the valid entries are little-endian
- * and invalid entries are host endian
- */
-static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp)
-{
- rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0;
-}
-
static inline struct page *be_alloc_pages(u32 size, gfp_t gfp)
{
u32 order = get_order(size);
struct be_rx_page_info *page_info;
struct be_queue_info *rxq = &rxo->q;
struct be_queue_info *rx_cq = &rxo->cq;
- struct be_eth_rx_compl *rxcp;
+ struct be_rx_compl_info *rxcp;
u16 tail;
/* First cleanup pending rx completions */
while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
be_rx_compl_discard(adapter, rxo, rxcp);
- be_rx_compl_reset(rxcp);
be_cq_notify(adapter, rx_cq->id, false, 1);
}
return IRQ_HANDLED;
}
-static inline bool do_gro(struct be_rx_obj *rxo,
- struct be_eth_rx_compl *rxcp, u8 err)
+static inline bool do_gro(struct be_rx_compl_info *rxcp)
{
- int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
-
- if (err)
- rxo->stats.rxcp_err++;
-
- return (tcp_frame && !err) ? true : false;
+ return (rxcp->tcpf && !rxcp->err) ? true : false;
}
static int be_poll_rx(struct napi_struct *napi, int budget)
struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq);
struct be_adapter *adapter = rxo->adapter;
struct be_queue_info *rx_cq = &rxo->cq;
- struct be_eth_rx_compl *rxcp;
+ struct be_rx_compl_info *rxcp;
u32 work_done;
- u16 num_rcvd;
- u8 err;
rxo->stats.rx_polls++;
for (work_done = 0; work_done < budget; work_done++) {
if (!rxcp)
break;
- err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags,
- rxcp);
/* Ignore flush completions */
- if (num_rcvd) {
- if (do_gro(rxo, rxcp, err))
+ if (rxcp->num_rcvd) {
+ if (do_gro(rxcp))
be_rx_compl_process_gro(adapter, rxo, rxcp);
else
be_rx_compl_process(adapter, rxo, rxcp);
}
-
- be_rx_compl_reset(rxcp);
+ be_rx_stats_update(rxo, rxcp);
}
/* Refill the queue */
if (status)
return status;
+ be_cmd_check_native_mode(adapter);
return 0;
}