|
@@ -70,7 +70,14 @@ static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id)
|
|
|
*/
|
|
|
static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
|
|
|
{
|
|
|
- if ((work->word2.snoip.err_code == 10) && (work->len <= 64)) {
|
|
|
+ int port;
|
|
|
+
|
|
|
+ if (octeon_has_feature(OCTEON_FEATURE_PKND))
|
|
|
+ port = work->word0.pip.cn68xx.pknd;
|
|
|
+ else
|
|
|
+ port = work->word1.cn38xx.ipprt;
|
|
|
+
|
|
|
+ if ((work->word2.snoip.err_code == 10) && (work->word1.len <= 64)) {
|
|
|
/*
|
|
|
* Ignore length errors on min size packets. Some
|
|
|
* equipment incorrectly pads packets to 64+4FCS
|
|
@@ -87,8 +94,8 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
|
|
|
* packet to determine if we can remove a non spec
|
|
|
* preamble and generate a correct packet.
|
|
|
*/
|
|
|
- int interface = cvmx_helper_get_interface_num(work->ipprt);
|
|
|
- int index = cvmx_helper_get_interface_index_num(work->ipprt);
|
|
|
+ int interface = cvmx_helper_get_interface_num(port);
|
|
|
+ int index = cvmx_helper_get_interface_index_num(port);
|
|
|
union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
|
|
|
|
|
|
gmxx_rxx_frm_ctl.u64 =
|
|
@@ -99,7 +106,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
|
|
|
cvmx_phys_to_ptr(work->packet_ptr.s.addr);
|
|
|
int i = 0;
|
|
|
|
|
|
- while (i < work->len - 1) {
|
|
|
+ while (i < work->word1.len - 1) {
|
|
|
if (*ptr != 0x55)
|
|
|
break;
|
|
|
ptr++;
|
|
@@ -109,18 +116,18 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
|
|
|
if (*ptr == 0xd5) {
|
|
|
/*
|
|
|
printk_ratelimited("Port %d received 0xd5 preamble\n",
|
|
|
- work->ipprt);
|
|
|
+ port);
|
|
|
*/
|
|
|
work->packet_ptr.s.addr += i + 1;
|
|
|
- work->len -= i + 5;
|
|
|
+ work->word1.len -= i + 5;
|
|
|
} else if ((*ptr & 0xf) == 0xd) {
|
|
|
/*
|
|
|
printk_ratelimited("Port %d received 0x?d preamble\n",
|
|
|
- work->ipprt);
|
|
|
+ port);
|
|
|
*/
|
|
|
work->packet_ptr.s.addr += i;
|
|
|
- work->len -= i + 4;
|
|
|
- for (i = 0; i < work->len; i++) {
|
|
|
+ work->word1.len -= i + 4;
|
|
|
+ for (i = 0; i < work->word1.len; i++) {
|
|
|
*ptr =
|
|
|
((*ptr & 0xf0) >> 4) |
|
|
|
((*(ptr + 1) & 0xf) << 4);
|
|
@@ -128,7 +135,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
|
|
|
}
|
|
|
} else {
|
|
|
printk_ratelimited("Port %d unknown preamble, packet dropped\n",
|
|
|
- work->ipprt);
|
|
|
+ port);
|
|
|
/*
|
|
|
cvmx_helper_dump_packet(work);
|
|
|
*/
|
|
@@ -138,7 +145,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
|
|
|
}
|
|
|
} else {
|
|
|
printk_ratelimited("Port %d receive error code %d, packet dropped\n",
|
|
|
- work->ipprt, work->word2.snoip.err_code);
|
|
|
+ port, work->word2.snoip.err_code);
|
|
|
cvm_oct_free_work(work);
|
|
|
return 1;
|
|
|
}
|
|
@@ -193,6 +200,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
struct sk_buff **pskb = NULL;
|
|
|
int skb_in_hw;
|
|
|
cvmx_wqe_t *work;
|
|
|
+ int port;
|
|
|
|
|
|
if (USE_ASYNC_IOBDMA && did_work_request)
|
|
|
work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH);
|
|
@@ -234,7 +242,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
prefetch(&skb->head);
|
|
|
prefetch(&skb->len);
|
|
|
}
|
|
|
- prefetch(cvm_oct_device[work->ipprt]);
|
|
|
+
|
|
|
+ if (octeon_has_feature(OCTEON_FEATURE_PKND))
|
|
|
+ port = work->word0.pip.cn68xx.pknd;
|
|
|
+ else
|
|
|
+ port = work->word1.cn38xx.ipprt;
|
|
|
+
|
|
|
+ prefetch(cvm_oct_device[port]);
|
|
|
|
|
|
/* Immediately throw away all packets with receive errors */
|
|
|
if (unlikely(work->word2.snoip.rcv_error)) {
|
|
@@ -251,7 +265,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
skb->data = skb->head + work->packet_ptr.s.addr -
|
|
|
cvmx_ptr_to_phys(skb->head);
|
|
|
prefetch(skb->data);
|
|
|
- skb->len = work->len;
|
|
|
+ skb->len = work->word1.len;
|
|
|
skb_set_tail_pointer(skb, skb->len);
|
|
|
packet_not_copied = 1;
|
|
|
} else {
|
|
@@ -259,7 +273,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
* We have to copy the packet. First allocate
|
|
|
* an skbuff for it.
|
|
|
*/
|
|
|
- skb = dev_alloc_skb(work->len);
|
|
|
+ skb = dev_alloc_skb(work->word1.len);
|
|
|
if (!skb) {
|
|
|
cvm_oct_free_work(work);
|
|
|
continue;
|
|
@@ -282,13 +296,14 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
else
|
|
|
ptr += 6;
|
|
|
}
|
|
|
- memcpy(skb_put(skb, work->len), ptr, work->len);
|
|
|
+ memcpy(skb_put(skb, work->word1.len), ptr,
|
|
|
+ work->word1.len);
|
|
|
/* No packet buffers to free */
|
|
|
} else {
|
|
|
int segments = work->word2.s.bufs;
|
|
|
union cvmx_buf_ptr segment_ptr =
|
|
|
work->packet_ptr;
|
|
|
- int len = work->len;
|
|
|
+ int len = work->word1.len;
|
|
|
|
|
|
while (segments--) {
|
|
|
union cvmx_buf_ptr next_ptr =
|
|
@@ -324,10 +339,9 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
}
|
|
|
packet_not_copied = 0;
|
|
|
}
|
|
|
-
|
|
|
- if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) &&
|
|
|
- cvm_oct_device[work->ipprt])) {
|
|
|
- struct net_device *dev = cvm_oct_device[work->ipprt];
|
|
|
+ if (likely((port < TOTAL_NUMBER_OF_PORTS) &&
|
|
|
+ cvm_oct_device[port])) {
|
|
|
+ struct net_device *dev = cvm_oct_device[port];
|
|
|
struct octeon_ethernet *priv = netdev_priv(dev);
|
|
|
|
|
|
/*
|
|
@@ -347,7 +361,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
|
|
/* Increment RX stats for virtual ports */
|
|
|
- if (work->ipprt >= CVMX_PIP_NUM_INPUT_PORTS) {
|
|
|
+ if (port >= CVMX_PIP_NUM_INPUT_PORTS) {
|
|
|
#ifdef CONFIG_64BIT
|
|
|
atomic64_add(1,
|
|
|
(atomic64_t *)&priv->stats.rx_packets);
|
|
@@ -382,7 +396,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
|
|
|
* doesn't exist.
|
|
|
*/
|
|
|
printk_ratelimited("Port %d not controlled by Linux, packet dropped\n",
|
|
|
- work->ipprt);
|
|
|
+ port);
|
|
|
dev_kfree_skb_irq(skb);
|
|
|
}
|
|
|
/*
|