Commit 83abb7d7 authored by Sunil Goutham's avatar Sunil Goutham Committed by David S. Miller

net: thunderx: Fix IOMMU translation faults

ACPI support has been added to ARM IOMMU driver in 4.10 kernel
and that has resulted in VNIC interfaces throwing translation
faults when kernel is booted with ACPI as driver was not using
DMA API. This patch fixes the issue by using DMA API which inturn
will create translation tables when IOMMU is enabled.

Also VNIC doesn't have a seperate receive buffer ring per receive
queue, so there is no 1:1 descriptor index matching between CQE_RX
and the index in buffer ring from where a buffer has been used for
DMA'ing. Unlike other NICs, here it's not possible to maintain dma
address to virt address mappings within the driver. This leaves us
no other choice but to use IOMMU's IOVA address conversion API to
get buffer's virtual address which can be given to network stack
for processing.
Signed-off-by: default avatarSunil Goutham <sgoutham@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3b12f73a
...@@ -269,6 +269,7 @@ struct nicvf { ...@@ -269,6 +269,7 @@ struct nicvf {
#define MAX_QUEUES_PER_QSET 8 #define MAX_QUEUES_PER_QSET 8
struct queue_set *qs; struct queue_set *qs;
struct nicvf_cq_poll *napi[8]; struct nicvf_cq_poll *napi[8];
void *iommu_domain;
u8 vf_id; u8 vf_id;
u8 sqs_id; u8 sqs_id;
bool sqs_mode; bool sqs_mode;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/iommu.h>
#include "nic_reg.h" #include "nic_reg.h"
#include "nic.h" #include "nic.h"
...@@ -525,7 +526,12 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev, ...@@ -525,7 +526,12 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev,
/* Get actual TSO descriptors and free them */ /* Get actual TSO descriptors and free them */
tso_sqe = tso_sqe =
(struct sq_hdr_subdesc *)GET_SQ_DESC(sq, hdr->rsvd2); (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, hdr->rsvd2);
nicvf_unmap_sndq_buffers(nic, sq, hdr->rsvd2,
tso_sqe->subdesc_cnt);
nicvf_put_sq_desc(sq, tso_sqe->subdesc_cnt + 1); nicvf_put_sq_desc(sq, tso_sqe->subdesc_cnt + 1);
} else {
nicvf_unmap_sndq_buffers(nic, sq, cqe_tx->sqe_ptr,
hdr->subdesc_cnt);
} }
nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1); nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
prefetch(skb); prefetch(skb);
...@@ -576,6 +582,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, ...@@ -576,6 +582,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct nicvf *nic = netdev_priv(netdev); struct nicvf *nic = netdev_priv(netdev);
struct nicvf *snic = nic;
int err = 0; int err = 0;
int rq_idx; int rq_idx;
...@@ -592,7 +599,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, ...@@ -592,7 +599,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
if (err && !cqe_rx->rb_cnt) if (err && !cqe_rx->rb_cnt)
return; return;
skb = nicvf_get_rcv_skb(nic, cqe_rx); skb = nicvf_get_rcv_skb(snic, cqe_rx);
if (!skb) { if (!skb) {
netdev_dbg(nic->netdev, "Packet not received\n"); netdev_dbg(nic->netdev, "Packet not received\n");
return; return;
...@@ -1643,6 +1650,9 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1643,6 +1650,9 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!pass1_silicon(nic->pdev)) if (!pass1_silicon(nic->pdev))
nic->hw_tso = true; nic->hw_tso = true;
/* Get iommu domain for iova to physical addr conversion */
nic->iommu_domain = iommu_get_domain_for_dev(dev);
pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid);
if (sdevid == 0xA134) if (sdevid == 0xA134)
nic->t88 = true; nic->t88 = true;
......
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
#define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13)) #define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13))
#define MAX_RCV_BUF_COUNT (1ULL << (RBDR_SIZE6 + 13)) #define MAX_RCV_BUF_COUNT (1ULL << (RBDR_SIZE6 + 13))
#define RBDR_THRESH (RCV_BUF_COUNT / 2) #define RBDR_THRESH (RCV_BUF_COUNT / 2)
#define DMA_BUFFER_LEN 2048 /* In multiples of 128bytes */ #define DMA_BUFFER_LEN 1536 /* In multiples of 128bytes */
#define RCV_FRAG_LEN (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \ #define RCV_FRAG_LEN (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
...@@ -301,6 +301,8 @@ struct queue_set { ...@@ -301,6 +301,8 @@ struct queue_set {
#define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT) #define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT)
void nicvf_unmap_sndq_buffers(struct nicvf *nic, struct snd_queue *sq,
int hdr_sqe, u8 subdesc_cnt);
void nicvf_config_vlan_stripping(struct nicvf *nic, void nicvf_config_vlan_stripping(struct nicvf *nic,
netdev_features_t features); netdev_features_t features);
int nicvf_set_qset_resources(struct nicvf *nic); int nicvf_set_qset_resources(struct nicvf *nic);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment