Contiki 3.x
eth.c
1 /*
2  * Copyright (C) 2015, Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <string.h>
32 #include <assert.h>
33 #include <stdio.h>
34 #include "contiki-net.h"
35 #include "dma.h"
36 #include "eth.h"
37 #include "helpers.h"
38 #include "syscalls.h"
39 #include "net/ip/uip.h"
40 #include "pci.h"
41 
43 
44 /* Refer to Intel Quark SoC X1000 Datasheet, Chapter 15 for more details on
45  * Ethernet device operation.
46  *
47  * This driver puts the Ethernet device into a very simple and space-efficient
48  * mode of operation. It only allocates a single packet descriptor for each of
49  * the transmit and receive directions, computes checksums on the CPU, and
50  * enables store-and-forward mode for both transmit and receive directions.
51  */
52 
53 /* Transmit descriptor */
54 typedef struct quarkX1000_eth_tx_desc {
55  /* First word of transmit descriptor */
56  union {
57  struct {
58  /* Only valid in half-duplex mode. */
59  uint32_t deferred_bit : 1;
60  uint32_t err_underflow : 1;
61  uint32_t err_excess_defer : 1;
62  uint32_t coll_cnt_slot_num : 4;
63  uint32_t vlan_frm : 1;
64  uint32_t err_excess_coll : 1;
65  uint32_t err_late_coll : 1;
66  uint32_t err_no_carrier : 1;
67  uint32_t err_carrier_loss : 1;
68  uint32_t err_ip_payload : 1;
69  uint32_t err_frm_flushed : 1;
70  uint32_t err_jabber_tout : 1;
71  /* OR of all other error bits. */
72  uint32_t err_summary : 1;
73  uint32_t err_ip_hdr : 1;
74  uint32_t tx_timestamp_stat : 1;
75  uint32_t vlan_ins_ctrl : 2;
76  uint32_t addr2_chained : 1;
77  uint32_t tx_end_of_ring : 1;
78  uint32_t chksum_ins_ctrl : 2;
79  uint32_t replace_crc : 1;
80  uint32_t tx_timestamp_en : 1;
81  uint32_t dis_pad : 1;
82  uint32_t dis_crc : 1;
83  uint32_t first_seg_in_frm : 1;
84  uint32_t last_seg_in_frm : 1;
85  uint32_t intr_on_complete : 1;
86  /* When set, descriptor is owned by DMA. */
87  uint32_t own : 1;
88  };
89  uint32_t tdes0;
90  };
91  /* Second word of transmit descriptor */
92  union {
93  struct {
94  uint32_t tx_buf1_sz : 13;
95  uint32_t : 3;
96  uint32_t tx_buf2_sz : 13;
97  uint32_t src_addr_ins_ctrl : 3;
98  };
99  uint32_t tdes1;
100  };
101  /* Pointer to frame data buffer */
102  uint8_t *buf1_ptr;
103  /* Unused, since this driver initializes only a single descriptor for each
104  * direction.
105  */
106  uint8_t *buf2_ptr;
107 } quarkX1000_eth_tx_desc_t;
108 
109 /* Transmit descriptor */
110 typedef struct quarkX1000_eth_rx_desc {
111  /* First word of receive descriptor */
112  union {
113  struct {
114  uint32_t ext_stat : 1;
115  uint32_t err_crc : 1;
116  uint32_t err_dribble_bit : 1;
117  uint32_t err_rx_mii : 1;
118  uint32_t err_rx_wdt : 1;
119  uint32_t frm_type : 1;
120  uint32_t err_late_coll : 1;
121  uint32_t giant_frm : 1;
122  uint32_t last_desc : 1;
123  uint32_t first_desc : 1;
124  uint32_t vlan_tag : 1;
125  uint32_t err_overflow : 1;
126  uint32_t length_err : 1;
127  uint32_t s_addr_filt_fail : 1;
128  uint32_t err_desc : 1;
129  uint32_t err_summary : 1;
130  uint32_t frm_len : 14;
131  uint32_t d_addr_filt_fail : 1;
132  uint32_t own : 1;
133  };
134  uint32_t rdes0;
135  };
136  /* Second word of receive descriptor */
137  union {
138  struct {
139  uint32_t rx_buf1_sz : 13;
140  uint32_t : 1;
141  uint32_t addr2_chained : 1;
142  uint32_t rx_end_of_ring : 1;
143  uint32_t rx_buf2_sz : 13;
144  uint32_t : 2;
145  uint32_t dis_int_compl : 1;
146  };
147  uint32_t rdes1;
148  };
149  /* Pointer to frame data buffer */
150  uint8_t *buf1_ptr;
151  /* Unused, since this driver initializes only a single descriptor for each
152  * direction.
153  */
154  uint8_t *buf2_ptr;
155 } quarkX1000_eth_rx_desc_t;
156 
157 /* Driver metadata associated with each Ethernet device */
158 typedef struct quarkX1000_eth_meta {
159  /* Transmit descriptor */
160  volatile quarkX1000_eth_tx_desc_t tx_desc;
161  /* Transmit DMA packet buffer */
162  volatile uint8_t tx_buf[ALIGN(UIP_BUFSIZE, 4)];
163  /* Receive descriptor */
164  volatile quarkX1000_eth_rx_desc_t rx_desc;
165  /* Receive DMA packet buffer */
166  volatile uint8_t rx_buf[ALIGN(UIP_BUFSIZE, 4)];
167 
168 #if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
169  /* Domain-defined metadata must fill an even number of pages, since that is
170  * the minimum granularity of access control supported by paging. However,
171  * using the "aligned(4096)" attribute causes the alignment of the kernel
172  * data section to increase, which causes problems when generating UEFI
173  * binaries, as is described in the linker script. Thus, it is necessary
174  * to manually pad the structure to fill a page. This only works if the
175  * sizes of the actual fields of the structure are collectively less than a
176  * page.
177  */
178  uint8_t pad[MIN_PAGE_SIZE -
179  (sizeof(quarkX1000_eth_tx_desc_t) +
180  ALIGN(UIP_BUFSIZE, 4) +
181  sizeof(quarkX1000_eth_rx_desc_t) +
182  ALIGN(UIP_BUFSIZE, 4))];
183 #endif
184 } __attribute__((packed)) quarkX1000_eth_meta_t;
185 
186 #define LOG_PFX "quarkX1000_eth: "
187 
188 #define MMIO_SZ 0x2000
189 
190 #define MAC_CONF_14_RMII_100M BIT(14)
191 #define MAC_CONF_11_DUPLEX BIT(11)
192 #define MAC_CONF_3_TX_EN BIT(3)
193 #define MAC_CONF_2_RX_EN BIT(2)
194 
195 #define OP_MODE_25_RX_STORE_N_FORWARD BIT(25)
196 #define OP_MODE_21_TX_STORE_N_FORWARD BIT(21)
197 #define OP_MODE_13_START_TX BIT(13)
198 #define OP_MODE_1_START_RX BIT(1)
199 
200 #define REG_ADDR_MAC_CONF 0x0000
201 #define REG_ADDR_MACADDR_HI 0x0040
202 #define REG_ADDR_MACADDR_LO 0x0044
203 #define REG_ADDR_TX_POLL_DEMAND 0x1004
204 #define REG_ADDR_RX_POLL_DEMAND 0x1008
205 #define REG_ADDR_RX_DESC_LIST 0x100C
206 #define REG_ADDR_TX_DESC_LIST 0x1010
207 #define REG_ADDR_DMA_OPERATION 0x1018
208 
209 PROT_DOMAINS_ALLOC(quarkX1000_eth_driver_t, drv);
210 static quarkX1000_eth_meta_t ATTR_BSS_DMA meta;
211 
212 void quarkX1000_eth_setup(uintptr_t meta_phys_base);
213 
214 /*---------------------------------------------------------------------------*/
215 SYSCALLS_DEFINE_SINGLETON(quarkX1000_eth_setup, drv, uintptr_t meta_phys_base)
216 {
217  uip_eth_addr mac_addr;
218  uint32_t mac_tmp1, mac_tmp2;
219  quarkX1000_eth_rx_desc_t rx_desc;
220  quarkX1000_eth_tx_desc_t tx_desc;
221  quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *loc_meta =
222  (quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *)PROT_DOMAINS_META(drv);
223 
224  prot_domains_enable_mmio();
225 
226  /* Read the MAC address from the device. */
227  PCI_MMIO_READL(drv, mac_tmp1, REG_ADDR_MACADDR_HI);
228  PCI_MMIO_READL(drv, mac_tmp2, REG_ADDR_MACADDR_LO);
229 
230  prot_domains_disable_mmio();
231 
232  /* Convert the data read from the device into the format expected by
233  * Contiki.
234  */
235  mac_addr.addr[5] = (uint8_t)(mac_tmp1 >> 8);
236  mac_addr.addr[4] = (uint8_t)mac_tmp1;
237  mac_addr.addr[3] = (uint8_t)(mac_tmp2 >> 24);
238  mac_addr.addr[2] = (uint8_t)(mac_tmp2 >> 16);
239  mac_addr.addr[1] = (uint8_t)(mac_tmp2 >> 8);
240  mac_addr.addr[0] = (uint8_t)mac_tmp2;
241 
242  printf(LOG_PFX "MAC address = %02x:%02x:%02x:%02x:%02x:%02x.\n",
243  mac_addr.addr[0],
244  mac_addr.addr[1],
245  mac_addr.addr[2],
246  mac_addr.addr[3],
247  mac_addr.addr[4],
248  mac_addr.addr[5]
249  );
250 
251  uip_setethaddr(mac_addr);
252 
253  /* Initialize transmit descriptor. */
254  tx_desc.tdes0 = 0;
255  tx_desc.tdes1 = 0;
256 
257  tx_desc.tx_end_of_ring = 1;
258  tx_desc.first_seg_in_frm = 1;
259  tx_desc.last_seg_in_frm = 1;
260  tx_desc.tx_end_of_ring = 1;
261 
262  META_WRITEL(loc_meta->tx_desc.tdes0, tx_desc.tdes0);
263  META_WRITEL(loc_meta->tx_desc.tdes1, tx_desc.tdes1);
264  META_WRITEL(loc_meta->tx_desc.buf1_ptr,
265  (uint8_t *)PROT_DOMAINS_META_OFF_TO_PHYS(
266  (uintptr_t)&loc_meta->tx_buf, meta_phys_base));
267  META_WRITEL(loc_meta->tx_desc.buf2_ptr, 0);
268 
269  /* Initialize receive descriptor. */
270  rx_desc.rdes0 = 0;
271  rx_desc.rdes1 = 0;
272 
273  rx_desc.own = 1;
274  rx_desc.first_desc = 1;
275  rx_desc.last_desc = 1;
276  rx_desc.rx_buf1_sz = UIP_BUFSIZE;
277  rx_desc.rx_end_of_ring = 1;
278 
279  META_WRITEL(loc_meta->rx_desc.rdes0, rx_desc.rdes0);
280  META_WRITEL(loc_meta->rx_desc.rdes1, rx_desc.rdes1);
281  META_WRITEL(loc_meta->rx_desc.buf1_ptr,
282  (uint8_t *)PROT_DOMAINS_META_OFF_TO_PHYS(
283  (uintptr_t)&loc_meta->rx_buf, meta_phys_base));
284  META_WRITEL(loc_meta->rx_desc.buf2_ptr, 0);
285 
286  prot_domains_enable_mmio();
287 
288  /* Install transmit and receive descriptors. */
289  PCI_MMIO_WRITEL(drv, REG_ADDR_RX_DESC_LIST,
290  PROT_DOMAINS_META_OFF_TO_PHYS(
291  (uintptr_t)&loc_meta->rx_desc, meta_phys_base));
292  PCI_MMIO_WRITEL(drv, REG_ADDR_TX_DESC_LIST,
293  PROT_DOMAINS_META_OFF_TO_PHYS(
294  (uintptr_t)&loc_meta->tx_desc, meta_phys_base));
295 
296  PCI_MMIO_WRITEL(drv, REG_ADDR_MAC_CONF,
297  /* Set the RMII speed to 100Mbps */
298  MAC_CONF_14_RMII_100M |
299  /* Enable full-duplex mode */
300  MAC_CONF_11_DUPLEX |
301  /* Enable transmitter */
302  MAC_CONF_3_TX_EN |
303  /* Enable receiver */
304  MAC_CONF_2_RX_EN);
305 
306  PCI_MMIO_WRITEL(drv, REG_ADDR_DMA_OPERATION,
307  /* Enable receive store-and-forward mode for simplicity. */
308  OP_MODE_25_RX_STORE_N_FORWARD |
309  /* Enable transmit store-and-forward mode for simplicity. */
310  OP_MODE_21_TX_STORE_N_FORWARD |
311  /* Place the transmitter state machine in the Running
312  state. */
313  OP_MODE_13_START_TX |
314  /* Place the receiver state machine in the Running state. */
315  OP_MODE_1_START_RX);
316 
317  prot_domains_disable_mmio();
318 
319  printf(LOG_PFX "Enabled 100M full-duplex mode.\n");
320 }
321 
322 /*---------------------------------------------------------------------------*/
323 /**
324  * \brief Poll for a received Ethernet frame.
325  * \param frame_len Will be set to the size of the received Ethernet frame or
326  * zero if no frame is available.
327  *
328  * If a frame is received, this procedure copies it into the
329  * global uip_buf buffer.
330  */
331 SYSCALLS_DEFINE_SINGLETON(quarkX1000_eth_poll, drv, uint16_t * frame_len)
332 {
333  uint16_t *loc_frame_len;
334  uint16_t frm_len = 0;
335  quarkX1000_eth_rx_desc_t tmp_desc;
336  quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *loc_meta =
337  (quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *)PROT_DOMAINS_META(drv);
338 
339  PROT_DOMAINS_VALIDATE_PTR(loc_frame_len, frame_len, sizeof(*frame_len));
340 
341  META_READL(tmp_desc.rdes0, loc_meta->rx_desc.rdes0);
342 
343  /* Check whether the RX descriptor is still owned by the device. If not,
344  * process the received frame or an error that may have occurred.
345  */
346  if(tmp_desc.own == 0) {
347  META_READL(tmp_desc.rdes1, loc_meta->rx_desc.rdes1);
348  if(tmp_desc.err_summary) {
349  fprintf(stderr,
350  LOG_PFX "Error receiving frame: RDES0 = %08x, RDES1 = %08x.\n",
351  tmp_desc.rdes0, tmp_desc.rdes1);
352  assert(0);
353  }
354 
355  frm_len = tmp_desc.frm_len;
356  assert(frm_len <= UIP_BUFSIZE);
357  MEMCPY_FROM_META(uip_buf, loc_meta->rx_buf, frm_len);
358 
359  /* Return ownership of the RX descriptor to the device. */
360  tmp_desc.own = 1;
361 
362  META_WRITEL(loc_meta->rx_desc.rdes0, tmp_desc.rdes0);
363 
364  prot_domains_enable_mmio();
365 
366  /* Request that the device check for an available RX descriptor, since
367  * ownership of the descriptor was just transferred to the device.
368  */
369  PCI_MMIO_WRITEL(drv, REG_ADDR_RX_POLL_DEMAND, 1);
370 
371  prot_domains_disable_mmio();
372  }
373 
374  *loc_frame_len = frm_len;
375 }
376 /*---------------------------------------------------------------------------*/
377 /**
378  * \brief Transmit the current Ethernet frame.
379  *
380  * This procedure will block indefinitely until the Ethernet device is
381  * ready to accept a new outgoing frame. It then copies the current
382  * Ethernet frame from the global uip_buf buffer to the device DMA
383  * buffer and signals to the device that a new frame is available to be
384  * transmitted.
385  */
386 SYSCALLS_DEFINE_SINGLETON(quarkX1000_eth_send, drv)
387 {
388  quarkX1000_eth_tx_desc_t tmp_desc;
389  quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *loc_meta =
390  (quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *)PROT_DOMAINS_META(drv);
391 
392  /* Wait until the TX descriptor is no longer owned by the device. */
393  do {
394  META_READL(tmp_desc.tdes0, loc_meta->tx_desc.tdes0);
395  } while(tmp_desc.own == 1);
396 
397  META_READL(tmp_desc.tdes1, loc_meta->tx_desc.tdes1);
398 
399  /* Check whether an error occurred transmitting the previous frame. */
400  if(tmp_desc.err_summary) {
401  fprintf(stderr,
402  LOG_PFX "Error transmitting frame: TDES0 = %08x, TDES1 = %08x.\n",
403  tmp_desc.tdes0, tmp_desc.tdes1);
404  assert(0);
405  }
406 
407  /* Transmit the next frame. */
408  assert(uip_len <= UIP_BUFSIZE);
409  MEMCPY_TO_META(loc_meta->tx_buf, uip_buf, uip_len);
410 
411  tmp_desc.tx_buf1_sz = uip_len;
412 
413  META_WRITEL(loc_meta->tx_desc.tdes1, tmp_desc.tdes1);
414 
415  tmp_desc.own = 1;
416 
417  META_WRITEL(loc_meta->tx_desc.tdes0, tmp_desc.tdes0);
418 
419  prot_domains_enable_mmio();
420 
421  /* Request that the device check for an available TX descriptor, since
422  * ownership of the descriptor was just transferred to the device.
423  */
424  PCI_MMIO_WRITEL(drv, REG_ADDR_TX_POLL_DEMAND, 1);
425 
426  prot_domains_disable_mmio();
427 }
428 /*---------------------------------------------------------------------------*/
429 /**
430  * \brief Initialize the first Quark X1000 Ethernet MAC.
431  *
432  * This procedure assumes that an MMIO range for the device was
433  * previously assigned, e.g. by firmware.
434  */
435 void
436 quarkX1000_eth_init(void)
437 {
438  pci_config_addr_t pci_addr = { .raw = 0 };
439 
440  /* PCI address from section 15.4 of Intel Quark SoC X1000 Datasheet. */
441 
442  pci_addr.dev = 20;
443  pci_addr.func = 6;
444 
445  /* Activate MMIO and DMA access. */
446  pci_command_enable(pci_addr, PCI_CMD_2_BUS_MST_EN | PCI_CMD_1_MEM_SPACE_EN);
447 
448  printf(LOG_PFX "Activated MMIO and DMA access.\n");
449 
450  pci_addr.reg_off = PCI_CONFIG_REG_BAR0;
451 
452  PROT_DOMAINS_INIT_ID(drv);
453  /* Configure the device MMIO range and initialize the driver structure. */
454  pci_init(&drv, pci_addr, MMIO_SZ,
455  (uintptr_t)&meta, sizeof(quarkX1000_eth_meta_t));
456  SYSCALLS_INIT(quarkX1000_eth_setup);
457  SYSCALLS_AUTHZ(quarkX1000_eth_setup, drv);
458  SYSCALLS_INIT(quarkX1000_eth_poll);
459  SYSCALLS_AUTHZ(quarkX1000_eth_poll, drv);
460  SYSCALLS_INIT(quarkX1000_eth_send);
461  SYSCALLS_AUTHZ(quarkX1000_eth_send, drv);
462 
463  quarkX1000_eth_setup(prot_domains_lookup_meta_phys_base(&drv));
464 }
465 /*---------------------------------------------------------------------------*/
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
uint32_t func
Function number.
Definition: pci.h:89
#define __attribute__(nothing)
Define attribute to nothing since it isn't handled by IAR.
Definition: iar.h:194
PCI configuration address.
Definition: pci.h:85
uint32_t dev
Device number.
Definition: pci.h:90
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:523
802.3 address
Definition: uip.h:129
#define uip_setethaddr(eaddr)
Specifiy the Ethernet MAC address.
Definition: uip_arp.h:131
Header file for the uIP TCP/IP stack.
Data associated with each protection domain that is owned by clients of that domain and used to ident...
Definition: prot-domains.h:247
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:173
uint32_t reg_off
Register/offset number.
Definition: pci.h:88