|
@@ -151,22 +151,26 @@ octeon_droq_destroy_ring_buffers(struct octeon_device *oct,
|
|
struct octeon_droq *droq)
|
|
struct octeon_droq *droq)
|
|
{
|
|
{
|
|
u32 i;
|
|
u32 i;
|
|
|
|
+ struct octeon_skb_page_info *pg_info;
|
|
|
|
|
|
for (i = 0; i < droq->max_count; i++) {
|
|
for (i = 0; i < droq->max_count; i++) {
|
|
- if (droq->recv_buf_list[i].buffer) {
|
|
|
|
- if (droq->desc_ring) {
|
|
|
|
- lio_unmap_ring_info(oct->pci_dev,
|
|
|
|
- (u64)droq->
|
|
|
|
- desc_ring[i].info_ptr,
|
|
|
|
- OCT_DROQ_INFO_SIZE);
|
|
|
|
- lio_unmap_ring(oct->pci_dev,
|
|
|
|
- (u64)droq->desc_ring[i].
|
|
|
|
- buffer_ptr,
|
|
|
|
- droq->buffer_size);
|
|
|
|
- }
|
|
|
|
- recv_buffer_free(droq->recv_buf_list[i].buffer);
|
|
|
|
- droq->recv_buf_list[i].buffer = NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ pg_info = &droq->recv_buf_list[i].pg_info;
|
|
|
|
+
|
|
|
|
+ if (pg_info->dma)
|
|
|
|
+ lio_unmap_ring(oct->pci_dev,
|
|
|
|
+ (u64)pg_info->dma);
|
|
|
|
+ pg_info->dma = 0;
|
|
|
|
+
|
|
|
|
+ if (pg_info->page)
|
|
|
|
+ recv_buffer_destroy(droq->recv_buf_list[i].buffer,
|
|
|
|
+ pg_info);
|
|
|
|
+
|
|
|
|
+ if (droq->desc_ring && droq->desc_ring[i].info_ptr)
|
|
|
|
+ lio_unmap_ring_info(oct->pci_dev,
|
|
|
|
+ (u64)droq->
|
|
|
|
+ desc_ring[i].info_ptr,
|
|
|
|
+ OCT_DROQ_INFO_SIZE);
|
|
|
|
+ droq->recv_buf_list[i].buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
octeon_droq_reset_indices(droq);
|
|
octeon_droq_reset_indices(droq);
|
|
@@ -181,11 +185,12 @@ octeon_droq_setup_ring_buffers(struct octeon_device *oct,
|
|
struct octeon_droq_desc *desc_ring = droq->desc_ring;
|
|
struct octeon_droq_desc *desc_ring = droq->desc_ring;
|
|
|
|
|
|
for (i = 0; i < droq->max_count; i++) {
|
|
for (i = 0; i < droq->max_count; i++) {
|
|
- buf = recv_buffer_alloc(oct, droq->q_no, droq->buffer_size);
|
|
|
|
|
|
+ buf = recv_buffer_alloc(oct, &droq->recv_buf_list[i].pg_info);
|
|
|
|
|
|
if (!buf) {
|
|
if (!buf) {
|
|
dev_err(&oct->pci_dev->dev, "%s buffer alloc failed\n",
|
|
dev_err(&oct->pci_dev->dev, "%s buffer alloc failed\n",
|
|
__func__);
|
|
__func__);
|
|
|
|
+ droq->stats.rx_alloc_failure++;
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -197,9 +202,7 @@ octeon_droq_setup_ring_buffers(struct octeon_device *oct,
|
|
/* map ring buffers into memory */
|
|
/* map ring buffers into memory */
|
|
desc_ring[i].info_ptr = lio_map_ring_info(droq, i);
|
|
desc_ring[i].info_ptr = lio_map_ring_info(droq, i);
|
|
desc_ring[i].buffer_ptr =
|
|
desc_ring[i].buffer_ptr =
|
|
- lio_map_ring(oct->pci_dev,
|
|
|
|
- droq->recv_buf_list[i].buffer,
|
|
|
|
- droq->buffer_size);
|
|
|
|
|
|
+ lio_map_ring(droq->recv_buf_list[i].buffer);
|
|
}
|
|
}
|
|
|
|
|
|
octeon_droq_reset_indices(droq);
|
|
octeon_droq_reset_indices(droq);
|
|
@@ -372,6 +375,7 @@ static inline struct octeon_recv_info *octeon_create_recv_info(
|
|
struct octeon_recv_pkt *recv_pkt;
|
|
struct octeon_recv_pkt *recv_pkt;
|
|
struct octeon_recv_info *recv_info;
|
|
struct octeon_recv_info *recv_info;
|
|
u32 i, bytes_left;
|
|
u32 i, bytes_left;
|
|
|
|
+ struct octeon_skb_page_info *pg_info;
|
|
|
|
|
|
info = &droq->info_list[idx];
|
|
info = &droq->info_list[idx];
|
|
|
|
|
|
@@ -389,9 +393,14 @@ static inline struct octeon_recv_info *octeon_create_recv_info(
|
|
bytes_left = (u32)info->length;
|
|
bytes_left = (u32)info->length;
|
|
|
|
|
|
while (buf_cnt) {
|
|
while (buf_cnt) {
|
|
- lio_unmap_ring(octeon_dev->pci_dev,
|
|
|
|
- (u64)droq->desc_ring[idx].buffer_ptr,
|
|
|
|
- droq->buffer_size);
|
|
|
|
|
|
+ {
|
|
|
|
+ pg_info = &droq->recv_buf_list[idx].pg_info;
|
|
|
|
+
|
|
|
|
+ lio_unmap_ring(octeon_dev->pci_dev,
|
|
|
|
+ (u64)pg_info->dma);
|
|
|
|
+ pg_info->page = NULL;
|
|
|
|
+ pg_info->dma = 0;
|
|
|
|
+ }
|
|
|
|
|
|
recv_pkt->buffer_size[i] =
|
|
recv_pkt->buffer_size[i] =
|
|
(bytes_left >=
|
|
(bytes_left >=
|
|
@@ -463,6 +472,7 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
|
|
void *buf = NULL;
|
|
void *buf = NULL;
|
|
u8 *data;
|
|
u8 *data;
|
|
u32 desc_refilled = 0;
|
|
u32 desc_refilled = 0;
|
|
|
|
+ struct octeon_skb_page_info *pg_info;
|
|
|
|
|
|
desc_ring = droq->desc_ring;
|
|
desc_ring = droq->desc_ring;
|
|
|
|
|
|
@@ -472,13 +482,22 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
|
|
* the buffer, else allocate.
|
|
* the buffer, else allocate.
|
|
*/
|
|
*/
|
|
if (!droq->recv_buf_list[droq->refill_idx].buffer) {
|
|
if (!droq->recv_buf_list[droq->refill_idx].buffer) {
|
|
- buf = recv_buffer_alloc(octeon_dev, droq->q_no,
|
|
|
|
- droq->buffer_size);
|
|
|
|
|
|
+ pg_info =
|
|
|
|
+ &droq->recv_buf_list[droq->refill_idx].pg_info;
|
|
|
|
+ /* Either recycle the existing pages or go for
|
|
|
|
+ * new page alloc
|
|
|
|
+ */
|
|
|
|
+ if (pg_info->page)
|
|
|
|
+ buf = recv_buffer_reuse(octeon_dev, pg_info);
|
|
|
|
+ else
|
|
|
|
+ buf = recv_buffer_alloc(octeon_dev, pg_info);
|
|
/* If a buffer could not be allocated, no point in
|
|
/* If a buffer could not be allocated, no point in
|
|
* continuing
|
|
* continuing
|
|
*/
|
|
*/
|
|
- if (!buf)
|
|
|
|
|
|
+ if (!buf) {
|
|
|
|
+ droq->stats.rx_alloc_failure++;
|
|
break;
|
|
break;
|
|
|
|
+ }
|
|
droq->recv_buf_list[droq->refill_idx].buffer =
|
|
droq->recv_buf_list[droq->refill_idx].buffer =
|
|
buf;
|
|
buf;
|
|
data = get_rbd(buf);
|
|
data = get_rbd(buf);
|
|
@@ -490,11 +509,8 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
|
|
droq->recv_buf_list[droq->refill_idx].data = data;
|
|
droq->recv_buf_list[droq->refill_idx].data = data;
|
|
|
|
|
|
desc_ring[droq->refill_idx].buffer_ptr =
|
|
desc_ring[droq->refill_idx].buffer_ptr =
|
|
- lio_map_ring(octeon_dev->pci_dev,
|
|
|
|
- droq->recv_buf_list[droq->
|
|
|
|
- refill_idx].buffer,
|
|
|
|
- droq->buffer_size);
|
|
|
|
-
|
|
|
|
|
|
+ lio_map_ring(droq->recv_buf_list[droq->
|
|
|
|
+ refill_idx].buffer);
|
|
/* Reset any previous values in the length field. */
|
|
/* Reset any previous values in the length field. */
|
|
droq->info_list[droq->refill_idx].length = 0;
|
|
droq->info_list[droq->refill_idx].length = 0;
|
|
|
|
|
|
@@ -600,6 +616,8 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
|
|
for (pkt = 0; pkt < pkt_count; pkt++) {
|
|
for (pkt = 0; pkt < pkt_count; pkt++) {
|
|
u32 pkt_len = 0;
|
|
u32 pkt_len = 0;
|
|
struct sk_buff *nicbuf = NULL;
|
|
struct sk_buff *nicbuf = NULL;
|
|
|
|
+ struct octeon_skb_page_info *pg_info;
|
|
|
|
+ void *buf;
|
|
|
|
|
|
info = &droq->info_list[droq->read_idx];
|
|
info = &droq->info_list[droq->read_idx];
|
|
octeon_swap_8B_data((u64 *)info, 2);
|
|
octeon_swap_8B_data((u64 *)info, 2);
|
|
@@ -619,7 +637,6 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
|
|
rh = &info->rh;
|
|
rh = &info->rh;
|
|
|
|
|
|
total_len += (u32)info->length;
|
|
total_len += (u32)info->length;
|
|
-
|
|
|
|
if (OPCODE_SLOW_PATH(rh)) {
|
|
if (OPCODE_SLOW_PATH(rh)) {
|
|
u32 buf_cnt;
|
|
u32 buf_cnt;
|
|
|
|
|
|
@@ -628,50 +645,44 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
|
|
droq->refill_count += buf_cnt;
|
|
droq->refill_count += buf_cnt;
|
|
} else {
|
|
} else {
|
|
if (info->length <= droq->buffer_size) {
|
|
if (info->length <= droq->buffer_size) {
|
|
- lio_unmap_ring(oct->pci_dev,
|
|
|
|
- (u64)droq->desc_ring[
|
|
|
|
- droq->read_idx].buffer_ptr,
|
|
|
|
- droq->buffer_size);
|
|
|
|
pkt_len = (u32)info->length;
|
|
pkt_len = (u32)info->length;
|
|
nicbuf = droq->recv_buf_list[
|
|
nicbuf = droq->recv_buf_list[
|
|
droq->read_idx].buffer;
|
|
droq->read_idx].buffer;
|
|
|
|
+ pg_info = &droq->recv_buf_list[
|
|
|
|
+ droq->read_idx].pg_info;
|
|
|
|
+ if (recv_buffer_recycle(oct, pg_info))
|
|
|
|
+ pg_info->page = NULL;
|
|
droq->recv_buf_list[droq->read_idx].buffer =
|
|
droq->recv_buf_list[droq->read_idx].buffer =
|
|
NULL;
|
|
NULL;
|
|
INCR_INDEX_BY1(droq->read_idx, droq->max_count);
|
|
INCR_INDEX_BY1(droq->read_idx, droq->max_count);
|
|
- skb_put(nicbuf, pkt_len);
|
|
|
|
droq->refill_count++;
|
|
droq->refill_count++;
|
|
} else {
|
|
} else {
|
|
- nicbuf = octeon_fast_packet_alloc(oct, droq,
|
|
|
|
- droq->q_no,
|
|
|
|
- (u32)
|
|
|
|
|
|
+ nicbuf = octeon_fast_packet_alloc((u32)
|
|
info->length);
|
|
info->length);
|
|
pkt_len = 0;
|
|
pkt_len = 0;
|
|
/* nicbuf allocation can fail. We'll handle it
|
|
/* nicbuf allocation can fail. We'll handle it
|
|
* inside the loop.
|
|
* inside the loop.
|
|
*/
|
|
*/
|
|
while (pkt_len < info->length) {
|
|
while (pkt_len < info->length) {
|
|
- int cpy_len;
|
|
|
|
|
|
+ int cpy_len, idx = droq->read_idx;
|
|
|
|
|
|
- cpy_len = ((pkt_len +
|
|
|
|
- droq->buffer_size) >
|
|
|
|
- info->length) ?
|
|
|
|
|
|
+ cpy_len = ((pkt_len + droq->buffer_size)
|
|
|
|
+ > info->length) ?
|
|
((u32)info->length - pkt_len) :
|
|
((u32)info->length - pkt_len) :
|
|
droq->buffer_size;
|
|
droq->buffer_size;
|
|
|
|
|
|
if (nicbuf) {
|
|
if (nicbuf) {
|
|
- lio_unmap_ring(oct->pci_dev,
|
|
|
|
- (u64)
|
|
|
|
- droq->desc_ring
|
|
|
|
- [droq->read_idx].
|
|
|
|
- buffer_ptr,
|
|
|
|
- droq->
|
|
|
|
- buffer_size);
|
|
|
|
octeon_fast_packet_next(droq,
|
|
octeon_fast_packet_next(droq,
|
|
nicbuf,
|
|
nicbuf,
|
|
cpy_len,
|
|
cpy_len,
|
|
- droq->
|
|
|
|
- read_idx
|
|
|
|
- );
|
|
|
|
|
|
+ idx);
|
|
|
|
+ buf = droq->recv_buf_list[idx].
|
|
|
|
+ buffer;
|
|
|
|
+ recv_buffer_fast_free(buf);
|
|
|
|
+ droq->recv_buf_list[idx].buffer
|
|
|
|
+ = NULL;
|
|
|
|
+ } else {
|
|
|
|
+ droq->stats.rx_alloc_failure++;
|
|
}
|
|
}
|
|
|
|
|
|
pkt_len += cpy_len;
|
|
pkt_len += cpy_len;
|
|
@@ -682,12 +693,13 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
|
|
}
|
|
}
|
|
|
|
|
|
if (nicbuf) {
|
|
if (nicbuf) {
|
|
- if (droq->ops.fptr)
|
|
|
|
|
|
+ if (droq->ops.fptr) {
|
|
droq->ops.fptr(oct->octeon_id,
|
|
droq->ops.fptr(oct->octeon_id,
|
|
- nicbuf, pkt_len,
|
|
|
|
- rh, &droq->napi);
|
|
|
|
- else
|
|
|
|
|
|
+ nicbuf, pkt_len,
|
|
|
|
+ rh, &droq->napi);
|
|
|
|
+ } else {
|
|
recv_buffer_free(nicbuf);
|
|
recv_buffer_free(nicbuf);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -695,16 +707,16 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
|
|
int desc_refilled = octeon_droq_refill(oct, droq);
|
|
int desc_refilled = octeon_droq_refill(oct, droq);
|
|
|
|
|
|
/* Flush the droq descriptor data to memory to be sure
|
|
/* Flush the droq descriptor data to memory to be sure
|
|
- * that when we update the credits the data in memory
|
|
|
|
- * is accurate.
|
|
|
|
- */
|
|
|
|
|
|
+ * that when we update the credits the data in memory
|
|
|
|
+ * is accurate.
|
|
|
|
+ */
|
|
wmb();
|
|
wmb();
|
|
writel((desc_refilled), droq->pkts_credit_reg);
|
|
writel((desc_refilled), droq->pkts_credit_reg);
|
|
/* make sure mmio write completes */
|
|
/* make sure mmio write completes */
|
|
mmiowb();
|
|
mmiowb();
|
|
}
|
|
}
|
|
|
|
|
|
- } /* for ( each packet )... */
|
|
|
|
|
|
+ } /* for (each packet)... */
|
|
|
|
|
|
/* Increment refill_count by the number of buffers processed. */
|
|
/* Increment refill_count by the number of buffers processed. */
|
|
droq->stats.pkts_received += pkt;
|
|
droq->stats.pkts_received += pkt;
|