1 /*************************************************************************
2 Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above
14 copyright notice, this list of conditions and the following
15 disclaimer in the documentation and/or other materials provided
16 with the distribution.
18 * Neither the name of Cavium Networks nor the names of
19 its contributors may be used to endorse or promote products
20 derived from this software without specific prior written
23 This Software, including technical data, may be subject to U.S. export control laws, including the U.S. Export Administration Act and its associated regulations, and may be subject to export or import regulations in other countries.
25 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26 AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
28 *************************************************************************/
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
39 #include <sys/socket.h>
42 #include <net/ethernet.h>
45 #include "wrapper-cvmx-includes.h"
46 #include "ethernet-headers.h"
48 /* You can define GET_MBUF_QOS() to override how the mbuf output function
49 determines which output queue is used. The default implementation
50 always uses the base queue for the port. If, for example, you wanted
51 to use the m->priority fieid, define GET_MBUF_QOS as:
52 #define GET_MBUF_QOS(m) ((m)->priority) */
54 #define GET_MBUF_QOS(m) 0
57 extern int pow_send_group;
63 * @param m Packet to send
64 * @param dev Device info structure
65 * @return Always returns zero
67 int cvm_oct_xmit(struct mbuf *m, struct ifnet *ifp)
69 cvmx_pko_command_word0_t pko_command;
70 cvmx_buf_ptr_t hw_buffer;
72 uint64_t old_scratch2;
75 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
77 int32_t buffers_to_free;
80 /* Prefetch the private data structure.
81 It is larger that one cache line */
82 CVMX_PREFETCH(priv, 0);
84 /* Start off assuming no drop */
87 /* The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to completely
88 remove "qos" in the event neither interface supports multiple queues
90 if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) ||
91 (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) {
92 qos = GET_MBUF_QOS(m);
95 else if (qos >= cvmx_pko_get_num_queues(priv->port))
100 if (USE_ASYNC_IOBDMA) {
101 /* Save scratch in case userspace is using it */
103 old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
104 old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH+8);
106 /* Assume we're going to be able t osend this packet. Fetch and increment
107 the number of pending packets for output */
108 cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH+8, FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
109 cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, priv->fau+qos*4, 1);
112 /* The CN3XXX series of parts has an errata (GMX-401) which causes the
113 GMX block to hang if a collision occurs towards the end of a
114 <68 byte packet. As a workaround for this, we pad packets to be
115 68 bytes whenever we are in half duplex mode. We don't handle
116 the case of having a small packet but no room to add the padding.
117 The kernel should always give us at least a cache line */
118 if (__predict_false(m->m_pkthdr.len < 64) && OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
119 cvmx_gmxx_prtx_cfg_t gmx_prt_cfg;
120 int interface = INTERFACE(priv->port);
121 int index = INDEX(priv->port);
124 /* We only need to pad packet in half duplex mode */
125 gmx_prt_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
126 if (gmx_prt_cfg.s.duplex == 0) {
127 static uint8_t pad[64];
129 if (!m_append(m, sizeof pad - m->m_pkthdr.len, pad))
130 printf("%s: unable to padd small packet.", __func__);
136 * If the packet is not fragmented.
138 if (m->m_pkthdr.len == m->m_len) {
139 /* Build the PKO buffer pointer */
141 hw_buffer.s.addr = cvmx_ptr_to_phys(m->m_data);
142 hw_buffer.s.pool = 0;
143 hw_buffer.s.size = m->m_len;
145 /* Build the PKO command */
147 pko_command.s.segs = 1;
156 * The packet is fragmented, we need to send a list of segments
157 * in memory we borrow from the WQE pool.
159 work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL);
160 gp = (uint64_t *)work;
163 for (n = m; n != NULL; n = n->m_next) {
164 if (segs == CVMX_FPA_WQE_POOL_SIZE / sizeof (uint64_t))
165 panic("%s: too many segments in packet; call m_collapse().", __func__);
167 /* Build the PKO buffer pointer */
169 hw_buffer.s.addr = cvmx_ptr_to_phys(n->m_data);
170 hw_buffer.s.pool = 0;
171 hw_buffer.s.size = n->m_len;
173 *gp++ = hw_buffer.u64;
177 /* Build the PKO buffer gather list pointer */
179 hw_buffer.s.addr = cvmx_ptr_to_phys(work);
180 hw_buffer.s.pool = CVMX_FPA_WQE_POOL;
181 hw_buffer.s.size = segs;
183 /* Build the PKO command */
185 pko_command.s.segs = segs;
186 pko_command.s.gather = 1;
189 /* Finish building the PKO command */
190 pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */
191 pko_command.s.dontfree = 1;
192 pko_command.s.reg0 = priv->fau+qos*4;
193 pko_command.s.reg0 = priv->fau+qos*4;
194 pko_command.s.total_bytes = m->m_pkthdr.len;
195 pko_command.s.size0 = CVMX_FAU_OP_SIZE_32;
196 pko_command.s.subone0 = 1;
198 /* Check if we can use the hardware checksumming */
199 if (USE_HW_TCPUDP_CHECKSUM &&
200 (m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) != 0) {
201 /* Use hardware checksum calc */
202 pko_command.s.ipoffp1 = ETHER_HDR_LEN + 1;
205 IF_LOCK(&priv->tx_free_queue[qos]);
206 if (USE_ASYNC_IOBDMA) {
207 /* Get the number of mbufs in use by the hardware */
209 in_use = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
210 buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH+8);
212 /* Get the number of mbufs in use by the hardware */
213 in_use = cvmx_fau_fetch_and_add32(priv->fau+qos*4, 1);
214 buffers_to_free = cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
217 cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos, CVMX_PKO_LOCK_CMD_QUEUE);
219 /* Drop this packet if we have too many already queued to the HW */
220 if (_IF_QFULL(&priv->tx_free_queue[qos])) {
223 /* Send the packet to the output queue */
225 if (__predict_false(cvmx_pko_send_packet_finish(priv->port, priv->queue + qos, pko_command, hw_buffer, CVMX_PKO_LOCK_CMD_QUEUE))) {
226 DEBUGPRINT("%s: Failed to send the packet\n", if_name(ifp));
230 if (USE_ASYNC_IOBDMA) {
231 /* Restore the scratch area */
232 cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
233 cvmx_scratch_write64(CVMX_SCR_SCRATCH+8, old_scratch2);
236 if (__predict_false(dropped)) {
238 cvmx_fau_atomic_add32(priv->fau+qos*4, -1);
241 /* Put this packet on the queue to be freed later */
242 _IF_ENQUEUE(&priv->tx_free_queue[qos], m);
244 /* Pass it to any BPF listeners. */
245 ETHER_BPF_MTAP(ifp, m);
248 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
250 /* Free mbufs not in use by the hardware */
251 if (_IF_QLEN(&priv->tx_free_queue[qos]) > in_use) {
252 while (_IF_QLEN(&priv->tx_free_queue[qos]) > in_use) {
253 _IF_DEQUEUE(&priv->tx_free_queue[qos], m);
257 IF_UNLOCK(&priv->tx_free_queue[qos]);
264 * Packet transmit to the POW
266 * @param m Packet to send
267 * @param dev Device info structure
268 * @return Always returns zero
270 int cvm_oct_xmit_pow(struct mbuf *m, struct ifnet *ifp)
272 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
276 /* Get a work queue entry */
277 cvmx_wqe_t *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL);
278 if (__predict_false(work == NULL)) {
279 DEBUGPRINT("%s: Failed to allocate a work queue entry\n", if_name(ifp));
285 /* Get a packet buffer */
286 packet_buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL);
287 if (__predict_false(packet_buffer == NULL)) {
288 DEBUGPRINT("%s: Failed to allocate a packet buffer\n",
290 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
296 /* Calculate where we need to copy the data to. We need to leave 8 bytes
297 for a next pointer (unused). We also need to include any configure
298 skip. Then we need to align the IP packet src and dest into the same
299 64bit word. The below calculation may add a little extra, but that
301 copy_location = packet_buffer + sizeof(uint64_t);
302 copy_location += ((CVMX_HELPER_FIRST_MBUFF_SKIP+7)&0xfff8) + 6;
304 /* We have to copy the packet since whoever processes this packet
305 will free it to a hardware pool. We can't use the trick of
306 counting outstanding packets like in cvm_oct_xmit */
307 m_copydata(m, 0, m->m_pkthdr.len, copy_location);
309 /* Fill in some of the work queue fields. We may need to add more
310 if the software at the other end needs them */
312 work->hw_chksum = m->csum;
314 work->len = m->m_pkthdr.len;
315 work->ipprt = priv->port;
316 work->qos = priv->port & 0x7;
317 work->grp = pow_send_group;
318 work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
319 work->tag = pow_send_group; /* FIXME */
320 work->word2.u64 = 0; /* Default to zero. Sets of zero later are commented out */
321 work->word2.s.bufs = 1;
322 work->packet_ptr.u64 = 0;
323 work->packet_ptr.s.addr = cvmx_ptr_to_phys(copy_location);
324 work->packet_ptr.s.pool = CVMX_FPA_PACKET_POOL;
325 work->packet_ptr.s.size = CVMX_FPA_PACKET_POOL_SIZE;
326 work->packet_ptr.s.back = (copy_location - packet_buffer)>>7;
328 panic("%s: POW transmit not quite implemented yet.", __func__);
330 if (m->protocol == htons(ETH_P_IP)) {
331 work->word2.s.ip_offset = 14;
333 work->word2.s.vlan_valid = 0; /* FIXME */
334 work->word2.s.vlan_cfi = 0; /* FIXME */
335 work->word2.s.vlan_id = 0; /* FIXME */
336 work->word2.s.dec_ipcomp = 0; /* FIXME */
338 work->word2.s.tcp_or_udp = (ip_hdr(m)->protocol == IP_PROTOCOL_TCP) || (ip_hdr(m)->protocol == IP_PROTOCOL_UDP);
340 work->word2.s.dec_ipsec = 0; /* FIXME */
341 work->word2.s.is_v6 = 0; /* We only support IPv4 right now */
342 work->word2.s.software = 0; /* Hardware would set to zero */
343 work->word2.s.L4_error = 0; /* No error, packet is internal */
345 work->word2.s.is_frag = !((ip_hdr(m)->frag_off == 0) || (ip_hdr(m)->frag_off == 1<<14));
347 work->word2.s.IP_exc = 0; /* Assume Linux is sending a good packet */
349 work->word2.s.is_bcast = (m->pkt_type == PACKET_BROADCAST);
350 work->word2.s.is_mcast = (m->pkt_type == PACKET_MULTICAST);
352 work->word2.s.not_IP = 0; /* This is an IP packet */
353 work->word2.s.rcv_error = 0; /* No error, packet is internal */
354 work->word2.s.err_code = 0; /* No error, packet is internal */
357 /* When copying the data, include 4 bytes of the ethernet header to
358 align the same way hardware does */
359 memcpy(work->packet_data, m->data + 10, sizeof(work->packet_data));
362 work->word2.snoip.vlan_valid = 0; /* FIXME */
363 work->word2.snoip.vlan_cfi = 0; /* FIXME */
364 work->word2.snoip.vlan_id = 0; /* FIXME */
365 work->word2.snoip.software = 0; /* Hardware would set to zero */
367 work->word2.snoip.is_rarp = m->protocol == htons(ETH_P_RARP);
368 work->word2.snoip.is_arp = m->protocol == htons(ETH_P_ARP);
369 work->word2.snoip.is_bcast = (m->pkt_type == PACKET_BROADCAST);
370 work->word2.snoip.is_mcast = (m->pkt_type == PACKET_MULTICAST);
371 work->word2.snoip.not_IP = 1; /* IP was done up above */
373 work->word2.snoip.rcv_error = 0; /* No error, packet is internal */
374 work->word2.snoip.err_code = 0; /* No error, packet is internal */
376 memcpy(work->packet_data, m->data, sizeof(work->packet_data));
380 /* Submit the packet to the POW */
381 cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, work->grp);
383 ifp->if_obytes += m->m_pkthdr.len;
390 * This function frees all mbufs that are currenty queued for TX.
392 * @param dev Device being shutdown
394 void cvm_oct_tx_shutdown(struct ifnet *ifp)
396 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
399 for (qos = 0; qos < 16; qos++) {
400 IF_DRAIN(&priv->tx_free_queue[qos]);