static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned int data; current_tx_ptr->skb = skb; /* * Is skb->data always 16-bit aligned? * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)? */ if ((((unsigned int)(skb->data)) & 0x02) == 2) { /* move skb->data to current_tx_ptr payload */ data = (unsigned int)(skb->data) - 2; *((unsigned short *)data) = (unsigned short)(skb->len); current_tx_ptr->desc_a.start_addr = (unsigned long)data; /* this is important! */ blackfin_dcache_flush_range(data, (data + (skb->len)) + 2); } else { *((unsigned short *)(current_tx_ptr->packet)) = (unsigned short)(skb->len); memcpy((char *)(current_tx_ptr->packet + 2), skb->data, (skb->len)); current_tx_ptr->desc_a.start_addr = (unsigned long)current_tx_ptr->packet; if (current_tx_ptr->status.status_word != 0) current_tx_ptr->status.status_word = 0; blackfin_dcache_flush_range((unsigned int)current_tx_ptr-> packet, (unsigned int)(current_tx_ptr-> packet + skb->len) + 2); } /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ if (bfin_read_DMA2_IRQ_STATUS() & 0x08) goto out; /* tx dma is not running */ bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a)); /* dma enabled, read from memory, size is 6 */ bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config); /* Turn on the EMAC tx */ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); out: adjust_tx_list(); current_tx_ptr = current_tx_ptr->next; dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); return 0; }
static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; u32 data_align = (unsigned long)(skb->data) & 0x3; current_tx_ptr->skb = skb; if (data_align == 0x2) { /* move skb->data to current_tx_ptr payload */ data = (u16 *)(skb->data) - 1; *data = (u16)(skb->len); current_tx_ptr->desc_a.start_addr = (u32)data; /* this is important! */ blackfin_dcache_flush_range((u32)data, (u32)((u8 *)data + skb->len + 4)); } else { *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, skb->len); current_tx_ptr->desc_a.start_addr = (u32)current_tx_ptr->packet; if (current_tx_ptr->status.status_word != 0) current_tx_ptr->status.status_word = 0; blackfin_dcache_flush_range( (u32)current_tx_ptr->packet, (u32)(current_tx_ptr->packet + skb->len + 2)); } /* make sure the internal data buffers in the core are drained * so that the DMA descriptors are completely written when the * DMA engine goes to fetch them below */ SSYNC(); /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN) goto out; /* tx dma is not running */ bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a)); /* dma enabled, read from memory, size is 6 */ bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config); /* Turn on the EMAC tx */ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); out: adjust_tx_list(); current_tx_ptr = current_tx_ptr->next; dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); return NETDEV_TX_OK; }
static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; u32 data_align = (unsigned long)(skb->data) & 0x3; current_tx_ptr->skb = skb; if (data_align == 0x2) { data = (u16 *)(skb->data) - 1; *data = (u16)(skb->len); current_tx_ptr->desc_a.start_addr = (u32)data; blackfin_dcache_flush_range((u32)data, (u32)((u8 *)data + skb->len + 4)); } else { *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, skb->len); current_tx_ptr->desc_a.start_addr = (u32)current_tx_ptr->packet; if (current_tx_ptr->status.status_word != 0) current_tx_ptr->status.status_word = 0; blackfin_dcache_flush_range( (u32)current_tx_ptr->packet, (u32)(current_tx_ptr->packet + skb->len + 2)); } SSYNC(); current_tx_ptr->desc_a.config |= DMAEN; if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN) goto out; bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a)); bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config); bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); out: adjust_tx_list(); current_tx_ptr = current_tx_ptr->next; dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); return NETDEV_TX_OK; }
static void bfin_sir_dma_tx_chars(struct net_device *dev) { struct bfin_sir_self *self = netdev_priv(dev); struct bfin_sir_port *port = self->sir_port; if (!port->tx_done) return; port->tx_done = 0; if (self->tx_buff.len == 0) { self->stats.tx_packets++; if (self->newspeed) { bfin_sir_set_speed(port, self->newspeed); self->speed = self->newspeed; self->newspeed = 0; } bfin_sir_enable_rx(port); port->tx_done = 1; netif_wake_queue(dev); return; } blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), (unsigned long)(self->tx_buff.data+self->tx_buff.len)); set_dma_config(port->tx_dma_channel, set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, DMA_SYNC_RESTART)); set_dma_start_addr(port->tx_dma_channel, (unsigned long)(self->tx_buff.data)); set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); set_dma_x_modify(port->tx_dma_channel, 1); enable_dma(port->tx_dma_channel); }
SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, int, op) { if (is_user_addr_valid(current, addr, len) != 0) return -EINVAL; if (op & DCACHE) blackfin_dcache_flush_range(addr, addr + len); if (op & ICACHE) blackfin_icache_flush_range(addr, addr + len); return 0; }
void flush_cache(unsigned long addr, unsigned long size) { /* no need to flush stuff in on chip memory (L1/L2/etc...) */ if (addr >= 0xE0000000) return; if (icache_status()) blackfin_icache_flush_range((void *)addr, (void *)(addr + size)); if (dcache_status()) blackfin_dcache_flush_range((void *)addr, (void *)(addr + size)); }
void flush_cache(unsigned long dummy1, unsigned long dummy2) { if ((dummy1 >= L1_ISRAM) && (dummy1 < L1_ISRAM_END)) return; if ((dummy1 >= DATA_BANKA_SRAM) && (dummy1 < DATA_BANKA_SRAM_END)) return; if ((dummy1 >= DATA_BANKB_SRAM) && (dummy1 < DATA_BANKB_SRAM_END)) return; if (icache_status()) blackfin_icache_flush_range((void*)dummy1, (void*)(dummy1 + dummy2)); if (dcache_status()) blackfin_dcache_flush_range((void*)dummy1, (void*)(dummy1 + dummy2)); return; }
static void dma_bitblit(void *dst, fastimage_t *logo, int x, int y) { if (dcache_status()) blackfin_dcache_flush_range(logo->data, logo->data + logo->size); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); /* Setup destination start address */ bfin_write_MDMA_D0_START_ADDR(dst + ((x & -2) * LCD_PIXEL_SIZE) + (y * LCD_X_RES * LCD_PIXEL_SIZE)); /* Setup destination xcount */ bfin_write_MDMA_D0_X_COUNT(logo->width * LCD_PIXEL_SIZE / DMA_SIZE16); /* Setup destination xmodify */ bfin_write_MDMA_D0_X_MODIFY(DMA_SIZE16); /* Setup destination ycount */ bfin_write_MDMA_D0_Y_COUNT(logo->height); /* Setup destination ymodify */ bfin_write_MDMA_D0_Y_MODIFY((LCD_X_RES - logo->width) * LCD_PIXEL_SIZE + DMA_SIZE16); /* Setup Source start address */ bfin_write_MDMA_S0_START_ADDR(logo->data); /* Setup Source xcount */ bfin_write_MDMA_S0_X_COUNT(logo->width * LCD_PIXEL_SIZE / DMA_SIZE16); /* Setup Source xmodify */ bfin_write_MDMA_S0_X_MODIFY(DMA_SIZE16); /* Setup Source ycount */ bfin_write_MDMA_S0_Y_COUNT(logo->height); /* Setup Source ymodify */ bfin_write_MDMA_S0_Y_MODIFY(DMA_SIZE16); /* Enable source DMA */ bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16 | DMA2D); SSYNC(); bfin_write_MDMA_D0_CONFIG(WNR | DMAEN | WDSIZE_16 | DMA2D); while (bfin_read_MDMA_D0_IRQ_STATUS() & DMA_RUN) ; bfin_write_MDMA_S0_IRQ_STATUS(bfin_read_MDMA_S0_IRQ_STATUS() | DMA_DONE | DMA_ERR); bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() | DMA_DONE | DMA_ERR); }
static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; u32 data_align = (unsigned long)(skb->data) & 0x3; union skb_shared_tx *shtx = skb_tx(skb); current_tx_ptr->skb = skb; if (data_align == 0x2) { /* move skb->data to current_tx_ptr payload */ data = (u16 *)(skb->data) - 1; *data = (u16)(skb->len); /* * When transmitting an Ethernet packet, the PTP_TSYNC module requires * a DMA_Length_Word field associated with the packet. The lower 12 bits * of this field are the length of the packet payload in bytes and the higher * 4 bits are the timestamping enable field. */ if (shtx->hardware) *data |= 0x1000; current_tx_ptr->desc_a.start_addr = (u32)data; /* this is important! */ blackfin_dcache_flush_range((u32)data, (u32)((u8 *)data + skb->len + 4)); } else { *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); /* enable timestamping for the sent packet */ if (shtx->hardware) *((u16 *)(current_tx_ptr->packet)) |= 0x1000; memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, skb->len); current_tx_ptr->desc_a.start_addr = (u32)current_tx_ptr->packet; if (current_tx_ptr->status.status_word != 0) current_tx_ptr->status.status_word = 0; blackfin_dcache_flush_range( (u32)current_tx_ptr->packet, (u32)(current_tx_ptr->packet + skb->len + 2)); } /* make sure the internal data buffers in the core are drained * so that the DMA descriptors are completely written when the * DMA engine goes to fetch them below */ SSYNC(); /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN) goto out; /* tx dma is not running */ bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a)); /* dma enabled, read from memory, size is 6 */ bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config); /* Turn on the EMAC tx */ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); out: adjust_tx_list(); bfin_tx_hwtstamp(dev, skb); current_tx_ptr = current_tx_ptr->next; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); return NETDEV_TX_OK; }
static void *__dma_memcpy(void *dest, const void *src, size_t size) { int direction; /* 1 - address decrease, 0 - address increase */ int flag_align; /* 1 - address aligned, 0 - address unaligned */ int flag_2D; /* 1 - 2D DMA needed, 0 - 1D DMA needed */ unsigned long flags; if (size <= 0) return NULL; local_irq_save(flags); if ((unsigned long)src < memory_end) blackfin_dcache_flush_range((unsigned int)src, (unsigned int)(src + size)); if ((unsigned long)dest < memory_end) blackfin_dcache_invalidate_range((unsigned int)dest, (unsigned int)(dest + size)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); if ((unsigned long)src < (unsigned long)dest) direction = 1; else direction = 0; if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0) && ((size % 2) == 0)) flag_align = 1; else flag_align = 0; if (size > 0x10000) /* size > 64K */ flag_2D = 1; else flag_2D = 0; /* Setup destination and source start address */ if (direction) { if (flag_align) { bfin_write_MDMA_D0_START_ADDR(dest + size - 2); bfin_write_MDMA_S0_START_ADDR(src + size - 2); } else { bfin_write_MDMA_D0_START_ADDR(dest + size - 1); bfin_write_MDMA_S0_START_ADDR(src + size - 1); } } else { bfin_write_MDMA_D0_START_ADDR(dest); bfin_write_MDMA_S0_START_ADDR(src); } /* Setup destination and source xcount */ if (flag_2D) { if (flag_align) { bfin_write_MDMA_D0_X_COUNT(1024 / 2); bfin_write_MDMA_S0_X_COUNT(1024 / 2); } else { bfin_write_MDMA_D0_X_COUNT(1024); bfin_write_MDMA_S0_X_COUNT(1024); } bfin_write_MDMA_D0_Y_COUNT(size >> 10); bfin_write_MDMA_S0_Y_COUNT(size >> 10); } else { if (flag_align) {
static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { struct tty_struct *tty = NULL; unsigned int status, ch, flg; static struct timeval anomaly_start = { .tv_sec = 0 }; status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); ch = UART_GET_CHAR(uart); uart->port.icount.rx++; #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) if (kgdb_connected && kgdboc_port_line == uart->port.line) if (ch == 0x3) {/* Ctrl + C */ kgdb_breakpoint(); return; } if (!uart->port.info || !uart->port.info->tty) return; #endif tty = uart->port.info->tty; if (ANOMALY_05000363) { /* The BF533 (and BF561) family of processors have a nice anomaly * where they continuously generate characters for a "single" break. * We have to basically ignore this flood until the "next" valid * character comes across. Due to the nature of the flood, it is * not possible to reliably catch bytes that are sent too quickly * after this break. So application code talking to the Blackfin * which sends a break signal must allow at least 1.5 character * times after the end of the break for things to stabilize. This * timeout was picked as it must absolutely be larger than 1 * character time +/- some percent. So 1.5 sounds good. All other * Blackfin families operate properly. Woo. */ if (anomaly_start.tv_sec) { struct timeval curr; suseconds_t usecs; if ((~ch & (~ch + 1)) & 0xff) goto known_good_char; do_gettimeofday(&curr); if (curr.tv_sec - anomaly_start.tv_sec > 1) goto known_good_char; usecs = 0; if (curr.tv_sec != anomaly_start.tv_sec) usecs += USEC_PER_SEC; usecs += curr.tv_usec - anomaly_start.tv_usec; if (usecs > UART_GET_ANOMALY_THRESHOLD(uart)) goto known_good_char; if (ch) anomaly_start.tv_sec = 0; else anomaly_start = curr; return; known_good_char: status &= ~BI; anomaly_start.tv_sec = 0; } } if (status & BI) { if (ANOMALY_05000363) if (bfin_revid() < 5) do_gettimeofday(&anomaly_start); uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto ignore_char; status &= ~(PE | FE); } if (status & PE) uart->port.icount.parity++; if (status & OE) uart->port.icount.overrun++; if (status & FE) uart->port.icount.frame++; status &= uart->port.read_status_mask; if (status & BI) flg = TTY_BREAK; else if (status & PE) flg = TTY_PARITY; else if (status & FE) flg = TTY_FRAME; else flg = TTY_NORMAL; if (uart_handle_sysrq_char(&uart->port, ch)) goto ignore_char; uart_insert_char(&uart->port, status, OE, ch, flg); ignore_char: tty_flip_buffer_push(tty); } static void bfin_serial_tx_chars(struct bfin_serial_port *uart) { struct circ_buf *xmit = &uart->port.info->xmit; /* * Check the modem control lines before * transmitting anything. */ bfin_serial_mctrl_check(uart); if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { #ifdef CONFIG_BF54x /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); #endif UART_CLEAR_IER(uart, ETBEI); return; } if (uart->port.x_char) { UART_PUT_CHAR(uart, uart->port.x_char); uart->port.icount.tx++; uart->port.x_char = 0; } while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); uart->port.icount.tx++; SSYNC(); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); } static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; spin_lock(&uart->port.lock); while (UART_GET_LSR(uart) & DR) bfin_serial_rx_chars(uart); spin_unlock(&uart->port.lock); return IRQ_HANDLED; } static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; spin_lock(&uart->port.lock); if (UART_GET_LSR(uart) & THRE) bfin_serial_tx_chars(uart); spin_unlock(&uart->port.lock); return IRQ_HANDLED; } #endif #ifdef CONFIG_SERIAL_BFIN_DMA static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) { struct circ_buf *xmit = &uart->port.info->xmit; uart->tx_done = 0; /* * Check the modem control lines before * transmitting anything. */ bfin_serial_mctrl_check(uart); if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { uart->tx_count = 0; uart->tx_done = 1; return; } if (uart->port.x_char) { UART_PUT_CHAR(uart, uart->port.x_char); uart->port.icount.tx++; uart->port.x_char = 0; } uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail)) uart->tx_count = UART_XMIT_SIZE - xmit->tail; blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail), (unsigned long)(xmit->buf+xmit->tail+uart->tx_count)); set_dma_config(uart->tx_dma_channel, set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, DMA_SYNC_RESTART)); set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); enable_dma(uart->tx_dma_channel); UART_SET_IER(uart, ETBEI); } static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) { struct tty_struct *tty = uart->port.info->port.tty; int i, flg, status; status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE); if (status & BI) { uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto dma_ignore_char; status &= ~(PE | FE); } if (status & PE) uart->port.icount.parity++; if (status & OE) uart->port.icount.overrun++; if (status & FE) uart->port.icount.frame++; status &= uart->port.read_status_mask; if (status & BI) flg = TTY_BREAK; else if (status & PE) flg = TTY_PARITY; else if (status & FE) flg = TTY_FRAME; else flg = TTY_NORMAL; for (i = uart->rx_dma_buf.tail; i != uart->rx_dma_buf.head; i++) { if (i >= UART_XMIT_SIZE) i = 0; if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg); } dma_ignore_char: tty_flip_buffer_push(tty); } void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos, flags; spin_lock_irqsave(&uart->port.lock, flags); uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; if (uart->rx_dma_nrows == DMA_RX_YCOUNT) uart->rx_dma_nrows = 0; x_pos = DMA_RX_XCOUNT - x_pos; if (x_pos == DMA_RX_XCOUNT) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; if (pos != uart->rx_dma_buf.tail) { uart->rx_dma_buf.head = pos; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } spin_unlock_irqrestore(&uart->port.lock, flags); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); }
static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { struct tty_struct *tty = NULL; unsigned int status, ch, flg; static struct timeval anomaly_start = { .tv_sec = 0 }; status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); ch = UART_GET_CHAR(uart); uart->port.icount.rx++; #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) if (kgdb_connected && kgdboc_port_line == uart->port.line && kgdboc_break_enabled) if (ch == 0x3) {/* Ctrl + C */ kgdb_breakpoint(); return; } if (!uart->port.state || !uart->port.state->port.tty) return; #endif tty = uart->port.state->port.tty; if (ANOMALY_05000363) { /* The BF533 (and BF561) family of processors have a nice anomaly * where they continuously generate characters for a "single" break. * We have to basically ignore this flood until the "next" valid * character comes across. Due to the nature of the flood, it is * not possible to reliably catch bytes that are sent too quickly * after this break. So application code talking to the Blackfin * which sends a break signal must allow at least 1.5 character * times after the end of the break for things to stabilize. This * timeout was picked as it must absolutely be larger than 1 * character time +/- some percent. So 1.5 sounds good. All other * Blackfin families operate properly. Woo. */ if (anomaly_start.tv_sec) { struct timeval curr; suseconds_t usecs; if ((~ch & (~ch + 1)) & 0xff) goto known_good_char; do_gettimeofday(&curr); if (curr.tv_sec - anomaly_start.tv_sec > 1) goto known_good_char; usecs = 0; if (curr.tv_sec != anomaly_start.tv_sec) usecs += USEC_PER_SEC; usecs += curr.tv_usec - anomaly_start.tv_usec; if (usecs > UART_GET_ANOMALY_THRESHOLD(uart)) goto known_good_char; if (ch) anomaly_start.tv_sec = 0; else anomaly_start = curr; return; known_good_char: status &= ~BI; anomaly_start.tv_sec = 0; } } if (status & BI) { if (ANOMALY_05000363) if (bfin_revid() < 5) do_gettimeofday(&anomaly_start); uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto ignore_char; status &= ~(PE | FE); } if (status & PE) uart->port.icount.parity++; if (status & OE) uart->port.icount.overrun++; if (status & FE) uart->port.icount.frame++; status &= uart->port.read_status_mask; if (status & BI) flg = TTY_BREAK; else if (status & PE) flg = TTY_PARITY; else if (status & FE) flg = TTY_FRAME; else flg = TTY_NORMAL; if (uart_handle_sysrq_char(&uart->port, ch)) goto ignore_char; uart_insert_char(&uart->port, status, OE, ch, flg); ignore_char: tty_flip_buffer_push(tty); } static void bfin_serial_tx_chars(struct bfin_serial_port *uart) { struct circ_buf *xmit = &uart->port.state->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { #ifdef CONFIG_BF54x /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); #endif /* Anomaly notes: * 05000215 - we always clear ETBEI within last UART TX * interrupt to end a string. It is always set * when start a new tx. */ UART_CLEAR_IER(uart, ETBEI); return; } if (uart->port.x_char) { UART_PUT_CHAR(uart, uart->port.x_char); uart->port.icount.tx++; uart->port.x_char = 0; } while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); uart->port.icount.tx++; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); } static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; while (UART_GET_LSR(uart) & DR) bfin_serial_rx_chars(uart); return IRQ_HANDLED; } static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { uart->scts = 0; uart_handle_cts_change(&uart->port, uart->scts); } #endif spin_lock(&uart->port.lock); if (UART_GET_LSR(uart) & THRE) bfin_serial_tx_chars(uart); spin_unlock(&uart->port.lock); return IRQ_HANDLED; } #endif #ifdef CONFIG_SERIAL_BFIN_DMA static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) { struct circ_buf *xmit = &uart->port.state->xmit; uart->tx_done = 0; if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { uart->tx_count = 0; uart->tx_done = 1; return; } if (uart->port.x_char) { UART_PUT_CHAR(uart, uart->port.x_char); uart->port.icount.tx++; uart->port.x_char = 0; } uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail)) uart->tx_count = UART_XMIT_SIZE - xmit->tail; blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail), (unsigned long)(xmit->buf+xmit->tail+uart->tx_count)); set_dma_config(uart->tx_dma_channel, set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, DMA_SYNC_RESTART)); set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); SSYNC(); enable_dma(uart->tx_dma_channel); UART_SET_IER(uart, ETBEI); } static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) { struct tty_struct *tty = uart->port.state->port.tty; int i, flg, status; status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE); if (status & BI) { uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto dma_ignore_char; status &= ~(PE | FE); } if (status & PE) uart->port.icount.parity++; if (status & OE) uart->port.icount.overrun++; if (status & FE) uart->port.icount.frame++; status &= uart->port.read_status_mask; if (status & BI) flg = TTY_BREAK; else if (status & PE) flg = TTY_PARITY; else if (status & FE) flg = TTY_FRAME; else flg = TTY_NORMAL; for (i = uart->rx_dma_buf.tail; ; i++) { if (i >= UART_XMIT_SIZE) i = 0; if (i == uart->rx_dma_buf.head) break; if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg); } dma_ignore_char: tty_flip_buffer_push(tty); } void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; dma_disable_irq_nosync(uart->rx_dma_channel); spin_lock_bh(&uart->rx_lock); /* 2D DMA RX buffer ring is used. Because curr_y_count and * curr_x_count can't be read as an atomic operation, * curr_y_count should be read before curr_x_count. When * curr_x_count is read, curr_y_count may already indicate * next buffer line. But, the position calculated here is * still indicate the old line. The wrong position data may * be smaller than current buffer tail, which cause garbages * are received if it is not prohibit. */ uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) uart->rx_dma_nrows = 0; x_pos = DMA_RX_XCOUNT - x_pos; if (x_pos == DMA_RX_XCOUNT) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; /* Ignore receiving data if new position is in the same line of * current buffer tail and small. */ if (pos > uart->rx_dma_buf.tail || uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { uart->rx_dma_buf.head = pos; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } spin_unlock_bh(&uart->rx_lock); dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); }
static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; current_tx_ptr->skb = skb; if (ANOMALY_05000285) { /* * TXDWA feature is not avaible to older revision < 0.3 silicon * of BF537 * * Only if data buffer is ODD WORD alignment, we do not * need to memcpy */ u32 data_align = (u32)(skb->data) & 0x3; if (data_align == 0x2) { /* move skb->data to current_tx_ptr payload */ data = (u16 *)(skb->data) - 1; *data = (u16)(skb->len); current_tx_ptr->desc_a.start_addr = (u32)data; /* this is important! */ blackfin_dcache_flush_range((u32)data, (u32)((u8 *)data + skb->len + 4)); } else { *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, skb->len); current_tx_ptr->desc_a.start_addr = (u32)current_tx_ptr->packet; if (current_tx_ptr->status.status_word != 0) current_tx_ptr->status.status_word = 0; blackfin_dcache_flush_range( (u32)current_tx_ptr->packet, (u32)(current_tx_ptr->packet + skb->len + 2)); } } else { /* * TXDWA feature is avaible to revision < 0.3 silicon of * BF537 and always avaible to BF52x */ u32 data_align = (u32)(skb->data) & 0x3; if (data_align == 0x0) { u16 sysctl = bfin_read_EMAC_SYSCTL(); sysctl |= TXDWA; bfin_write_EMAC_SYSCTL(sysctl); /* move skb->data to current_tx_ptr payload */ data = (u16 *)(skb->data) - 2; *data = (u16)(skb->len); current_tx_ptr->desc_a.start_addr = (u32)data; /* this is important! */ blackfin_dcache_flush_range( (u32)data, (u32)((u8 *)data + skb->len + 4)); } else if (data_align == 0x2) { u16 sysctl = bfin_read_EMAC_SYSCTL(); sysctl &= ~TXDWA; bfin_write_EMAC_SYSCTL(sysctl); /* move skb->data to current_tx_ptr payload */ data = (u16 *)(skb->data) - 1; *data = (u16)(skb->len); current_tx_ptr->desc_a.start_addr = (u32)data; /* this is important! */ blackfin_dcache_flush_range( (u32)data, (u32)((u8 *)data + skb->len + 4)); } else { u16 sysctl = bfin_read_EMAC_SYSCTL(); sysctl &= ~TXDWA; bfin_write_EMAC_SYSCTL(sysctl); *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, skb->len); current_tx_ptr->desc_a.start_addr = (u32)current_tx_ptr->packet; if (current_tx_ptr->status.status_word != 0) current_tx_ptr->status.status_word = 0; blackfin_dcache_flush_range( (u32)current_tx_ptr->packet, (u32)(current_tx_ptr->packet + skb->len + 2)); } } /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ if (bfin_read_DMA2_IRQ_STATUS() & 0x08) goto out; /* tx dma is not running */ bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a)); /* dma enabled, read from memory, size is 6 */ bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config); /* Turn on the EMAC tx */ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); out: adjust_tx_list(); current_tx_ptr = current_tx_ptr->next; dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); return 0; }