embox
1/**
2* @file
3* @brief RDC R6040 PCI Fast Ethernet MAC support
4* @description Low level ring-buffer manipulation for r6040 ethernet.
5*
6* @date 25.03.11
7* @author Nikolay Korotky
8*/
9
10#include <asm/io.h>11#include <string.h>12#include <unistd.h>13#include <stdint.h>14#include <kernel/time/ktime.h>15#include <embox/unit.h>16#include <net/l2/ethernet.h>17#include <net/skbuff.h>18#include <net/netdevice.h>19#include <kernel/irq.h>20#include <net/l0/net_entry.h>21
22#include "r6040.h"23
24EMBOX_UNIT_INIT(r6040_init);25
26#define INTERRUPTS_ENABLE 027
28/* PHY CHIP Address */
29#define PHY1_ADDR 1 /* For MAC1 */30#define PHY2_ADDR 3 /* For MAC2 */31#define PHY_MODE 0x3100 /* PHY CHIP Register 0 */32#define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */33
34/* RDC MAC I/O Size */
35#define R6040_IO_SIZE 25636
37//TODO: get from PCI
38#define IOADDR 0xe80039
40/* MAC registers */
41#define MCR0 (IOADDR + 0x00) /* Control register 0 */42#define MCR0_PROMISC 0x0020 /* Promiscuous mode */43#define MCR0_HASH_EN 0x0100 /* Enable multicast hash table function */44#define MCR1 (IOADDR + 0x04) /* Control register 1 */45#define MAC_RST 0x0001 /* Reset the MAC */46#define MBCR (IOADDR + 0x08) /* Bus control */47#define MT_ICR (IOADDR + 0x0C) /* TX interrupt control */48#define MR_ICR (IOADDR + 0x10) /* RX interrupt control */49#define MTPR (IOADDR + 0x14) /* TX poll command register */50#define MR_BSR (IOADDR + 0x18) /* RX buffer size */51#define MR_DCR (IOADDR + 0x1A) /* RX descriptor control */52#define MLSR (IOADDR + 0x1C) /* Last status */53#define MMDIO (IOADDR + 0x20) /* MDIO control register */54#define MDIO_WRITE 0x4000 /* MDIO write */55#define MDIO_READ 0x2000 /* MDIO read */56#define MMRD (IOADDR + 0x24) /* MDIO read data register */57#define MMWD (IOADDR + 0x28) /* MDIO write data register */58#define TX_START_LOW (IOADDR + 0x2c) /* TX descriptor start address 0 */59#define TX_START_HIGH (IOADDR + 0x30) /* TX descriptor start address 1 */60#define RX_START_LOW (IOADDR + 0x34) /* RX descriptor start address 0 */61#define RX_START_HIGH (IOADDR + 0x38) /* RX descriptor start address 1 */62#define MISR (IOADDR + 0x3c) /* Status register */63#define MIER (IOADDR + 0x40) /* INT enable register */64#define MSK_INT 0x0000 /* Mask off interrupts */65#define RX_FINISH 0x0001 /* RX finished */66#define RX_NO_DESC 0x0002 /* No RX descriptor available */67#define RX_FIFO_FULL 0x0004 /* RX FIFO full */68#define RX_EARLY 0x0008 /* RX early */69#define TX_FINISH 0x0010 /* TX finished */70#define TX_EARLY 0x0080 /* TX early */71#define EVENT_OVRFL 0x0100 /* Event counter overflow */72#define LINK_CHANGED 0x0200 /* PHY link changed */73#define ME_CISR (IOADDR + 0x44) /* Event counter INT status */74#define ME_CIER (IOADDR + 0x48) /* Event counter INT enable */75#define MR_CNT (IOADDR + 0x50) /* Successfully received packet counter */76#define ME_CNT0 (IOADDR + 0x52) /* Event counter 0 */77#define ME_CNT1 (IOADDR + 0x54) /* Event counter 1 */78#define ME_CNT2 (IOADDR + 0x56) /* Event counter 2 */79#define ME_CNT3 (IOADDR + 0x58) /* Event counter 3 */80#define MT_CNT (IOADDR + 0x5A) /* Successfully transmit packet counter */81#define ME_CNT4 (IOADDR + 0x5C) /* Event counter 4 */82#define MP_CNT (IOADDR + 0x5E) /* Pause frame counter register */83#define MAR0 (IOADDR + 0x60) /* Hash table 0 */84#define MAR1 (IOADDR + 0x62) /* Hash table 1 */85#define MAR2 (IOADDR + 0x64) /* Hash table 2 */86#define MAR3 (IOADDR + 0x66) /* Hash table 3 */87
88#define MAC_SM (IOADDR + 0xAC) /* MAC status machine */89
90#define TX_DCNT 0x80 /* TX descriptor count */91#define RX_DCNT 0x80 /* RX descriptor count */92#define MAX_BUF_SIZE 0x60093//#define RX_DESC_SIZE (RX_DCNT * sizeof(struct eth_desc))
94//#define TX_DESC_SIZE (TX_DCNT * sizeof(struct eth_desc))
95#define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */96
97/* Descriptor status */
98#define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */99#define DSC_RX_OK 0x4000 /* RX was successful */100#define DSC_RX_ERR 0x0800 /* RX PHY error */101#define DSC_RX_ERR_DRI 0x0400 /* RX dribble packet */102#define DSC_RX_ERR_BUF 0x0200 /* RX length exceeds buffer size */103#define DSC_RX_ERR_LONG 0x0100 /* RX length > maximum packet length */104#define DSC_RX_ERR_RUNT 0x0080 /* RX packet length < 64 byte */105#define DSC_RX_ERR_CRC 0x0040 /* RX CRC error */106#define DSC_RX_BCAST 0x0020 /* RX broadcast (no error) */107#define DSC_RX_MCAST 0x0010 /* RX multicast (no error) */108#define DSC_RX_MCH_HIT 0x0008 /* RX multicast hit in hash table (no error) */109#define DSC_RX_MIDH_HIT 0x0004 /* RX MID table hit (no error) */110#define DSC_RX_IDX_MID_MASK 3 /* RX mask for the index of matched MIDx */111
112/* RX and TX interrupts that we handle */
113#define RX_INTS (RX_FIFO_FULL | RX_NO_DESC | RX_FINISH)114#define TX_INTS (TX_FINISH)115#define INT_MASK (RX_INTS | TX_INTS)116
117/**
118* Descriptor definition and manip functions.
119* doubles as the TX and RX descriptor
120*/
121typedef struct eth_desc {122volatile uint16_t status;123uint16_t dlen;124unsigned char *buf;125struct eth_desc *DNX;126unsigned short HIDX;127unsigned short Reserved1;128unsigned short Reserved2;129/* Extra info, used by driver */130unsigned short dlen_orig;131} __attribute__((aligned(32))) eth_desc_t;132
133static uint8_t descrxbuff[0x800];134static uint8_t etherrxbuff[0x800];135
136/* Pass in the next pointer */
137static eth_desc_t *rxd_init(size_t pkt_size) {138eth_desc_t *rxd = (eth_desc_t *) descrxbuff;139unsigned char *pkt = (unsigned char *) etherrxbuff;140
141/* Clear it */142memset(rxd, 0, sizeof(eth_desc_t));143
144/* clear pkt area */145memset(pkt, 0, pkt_size);146
147/* Make this one owned by the MAC */148rxd->status = DSC_OWNER_MAC;149
150/* Set the buffer pointer */151rxd->buf = pkt;152rxd->dlen = pkt_size;153
154return rxd;155}
156
157static void r6040_tx_enable(void) {158unsigned short tmp = in16(MCR0);159out16(tmp | (1 << 12), MCR0);160}
161
162static void r6040_tx_disable(void) {163unsigned short tmp = in16(MCR0);164out16(tmp & ~(1 << 12), MCR0);165}
166
167void r6040_rx_enable(void) {168unsigned short tmp = in16(MCR0);169out16(tmp | (1 << 1), MCR0);170// out16(2, MCR0);
171}
172
173static void r6040_rx_disable(void) {174out8(0, MCR0);175}
176
177static void r6040_set_tx_start(eth_desc_t* desc) {178unsigned long tmp = (unsigned long) desc;179out16((tmp & 0xffff), TX_START_LOW);180tmp >>= 16;181out16((tmp & 0xffff), TX_START_HIGH);182}
183
184static void r6040_set_rx_start(eth_desc_t* desc) {185unsigned long tmp = (unsigned long) desc;186out16((tmp & 0xffff), RX_START_LOW);187tmp >>= 16;188out16((tmp & 0xffff), RX_START_HIGH);189}
190#include <kernel/printk.h>191#if INTERRUPTS_ENABLE192/* The RDC interrupt handler */
193static irq_return_t irq_handler(unsigned int irq_num, void *dev_id) {194uint16_t misr, status;195
196printk("IRQ!\n");197
198/* Save MIER */199misr = in16(MIER);200/* Mask off RDC MAC interrupt */201out16(MSK_INT, MIER);202/* Read MISR status and clear */203status = in16(MISR);204
205if (status == 0x0000 || status == 0xffff) {206/* Restore RDC MAC interrupt */207out16(misr, MIER);208return IRQ_NONE;209}210//TODO:211
212/* Restore RDC MAC interrupt */213out16(misr, MIER);214return IRQ_HANDLED;215}
216#endif217/* Interface */
218
219/* Keep track of what we've allocated, so we can easily walk it */
220eth_desc_t *g_rx_descriptor_list[R6040_RX_DESCRIPTORS];221eth_desc_t *g_rx_descriptor_next;222eth_desc_t *g_tx_descriptor_next;223
224#if 0225/* Disable packet reception */
226void r6040_done(void) {227out8(0, MCR0);228}
229#endif230
231static void discard_descriptor(void) {232/* reset the length field to original value. */233g_rx_descriptor_next->dlen = g_rx_descriptor_next->dlen_orig;234g_rx_descriptor_next->status = DSC_OWNER_MAC; /* give back to the MAC */235g_rx_descriptor_next = g_rx_descriptor_next->DNX; /* Move along */236}
237
238/* Returns size of pkt, or zero if none received */
239size_t r6040_rx(unsigned char* pkt, size_t max_len) {240size_t ret = 0;241printk("MIER=0x%08x\n", *((unsigned int *) MIER));242printk("MISR=0x%08x\n", *((unsigned int *) MISR));243printk("MR_ICR=0x%08x\n", *((unsigned int *) MR_ICR));244
245if (g_rx_descriptor_next->status & DSC_OWNER_MAC) {246/* Still owned by the MAC, nothing received */247return ret;248}249
250if (!(g_rx_descriptor_next->status & DSC_RX_OK)) {251/* Descriptor descarded with error */252discard_descriptor();253return ret;254}255
256/* If the buffer isn't long enough discard this packet */257if (g_rx_descriptor_next->dlen > max_len) {258/* Descriptor descarded (buffer too short) */259discard_descriptor();260return ret;261}262
263/* Otherwise copy out and advance buffer pointer */264
265memcpy(pkt, g_rx_descriptor_next->buf, g_rx_descriptor_next->dlen);266ret = g_rx_descriptor_next->dlen;267ret -= 4; /* chop the checksum, we don't need it */268discard_descriptor();269return ret;270}
271
272/* queue packet for transmission */
273void r6040_tx(unsigned char* pkt, size_t length) {274r6040_tx_disable();275
276/* copy this packet into the transmit descriptor */277memset(g_tx_descriptor_next->buf, 0, 60);278
279memcpy(g_tx_descriptor_next->buf, pkt, length);280g_tx_descriptor_next->dlen = (length < 60) ? 60 : length;281
282/* Copy the descriptor address (will have been set to zero by last op) */283r6040_set_tx_start(g_tx_descriptor_next);284
285/* Make the mac own it */286g_tx_descriptor_next->status = DSC_OWNER_MAC;287
288//desc_dump(g_tx_descriptor_next);289
290/* Start xmit */291r6040_tx_enable();292
293/* poll for mac to no longer own it */294while (g_tx_descriptor_next->status & DSC_OWNER_MAC) {};295/* Stop any other activity */296r6040_tx_disable();297
298//desc_dump(g_tx_descriptor_next);299}
300
301unsigned short r6040_mdio_read(int reg, int phy) {302out8(MDIO_READ + reg + (phy << 8), MMDIO);303/* Wait for the read bit to be cleared */304while (in16(MMDIO) & MDIO_READ);305return in16(MMRD);306}
307
308/* Wait for linkup, or timeout. */
309int r6040_wait_linkup(void) {310unsigned short tmp, i;311
312for (i = 0; i < 300; i++) {313/* Check if link up. */314tmp = r6040_mdio_read(1, 1) & (1 << 2);315if (tmp) {316return 1;317}318/* Wait 10mS more */319ksleep(10);320}321return 0;322}
323
324int r6040_open(struct net_device *dev) {325#if INTERRUPTS_ENABLE326if (-1 == irq_attach(0x0a, irq_handler, 0, dev, "RDC r6040")) {327return -1;328}329out16(0, MT_ICR);330out16(0, MR_ICR);331out16(INT_MASK, MIER);332#endif333return 0;334
335}
336#if INTERRUPTS_ENABLE337static int r6040_stop(struct net_device *dev) {338return 0;339
340}
341
342static const struct net_driver r6040_drv_ops = {343// .xmit = r6040_xmit,
344.start = r6040_open,345.stop = r6040_stop,346// .set_macaddr = set_mac_address
347};348#endif349
350
351/* setup descriptors, start packet reception */
352static int r6040_init(void) {353size_t i;354r6040_wait_linkup();355r6040_rx_disable();356r6040_tx_disable();357for (i = 0; i < R6040_RX_DESCRIPTORS; i++) {358/* most packets will be no larger than this */359g_rx_descriptor_list[i] = rxd_init(1536);360if (i) {361g_rx_descriptor_list[i - 1]->DNX = g_rx_descriptor_list[i];362}363}364/* Make ring buffer */365g_rx_descriptor_list[R6040_RX_DESCRIPTORS - 1]->DNX = g_rx_descriptor_list[0];366r6040_set_rx_start(g_rx_descriptor_list[0]);367g_rx_descriptor_next = g_rx_descriptor_list[0];368g_tx_descriptor_next = rxd_init(1536);369
370r6040_rx_enable();371return 0;372}
373