skb = netdev_alloc_skb(ugeth->ndev,
ugeth->ug_info->uf_info.max_rx_buf_length +
UCC_GETH_RX_DATA_BUF_ALIGNMENT); if (!skb) return NULL;
/* We need the data buffer to be aligned properly. We will reserve * as many bytes as needed to align the data properly
*/
skb_reserve(skb,
UCC_GETH_RX_DATA_BUF_ALIGNMENT -
(((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
1)));
for (i = 0; i < num_entries; i++) { if ((snum = qe_get_snum()) < 0) { if (netif_msg_ifup(ugeth))
pr_err("Can not get SNUM\n"); return snum;
} if ((i == 0) && skip_page_for_first_entry) /* First entry of Rx does not have page */
init_enet_offset = 0; else {
init_enet_offset =
qe_muram_alloc(thread_size, thread_alignment); if (IS_ERR_VALUE(init_enet_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory\n");
qe_put_snum((u8) snum); return -ENOMEM;
}
}
*(p_start++) =
((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset
| risc;
}
return 0;
}
staticint return_init_enet_entries(struct ucc_geth_private *ugeth,
u32 *p_start,
u8 num_entries, unsignedint risc, int skip_page_for_first_entry)
{
u32 init_enet_offset;
u8 i; int snum;
for (i = 0; i < num_entries; i++) {
u32 val = *p_start;
/* Check that this entry was actually valid --
needed in case failed in allocations */ if ((val & ENET_INIT_PARAM_RISC_MASK) == risc) {
snum =
(u32) (val & ENET_INIT_PARAM_SNUM_MASK) >>
ENET_INIT_PARAM_SNUM_SHIFT;
qe_put_snum((u8) snum); if (!((i == 0) && skip_page_for_first_entry)) { /* First entry of Rx does not have page */
init_enet_offset =
(val & ENET_INIT_PARAM_PTR_MASK);
qe_muram_free(init_enet_offset);
}
*p_start++ = 0;
}
}
value = (u32) (alt_beb_truncation << HALFDUP_ALT_BEB_TRUNCATION_SHIFT);
if (alt_beb)
value |= HALFDUP_ALT_BEB; if (back_pressure_no_backoff)
value |= HALFDUP_BACK_PRESSURE_NO_BACKOFF; if (no_backoff)
value |= HALFDUP_NO_BACKOFF; if (excess_defer)
value |= HALFDUP_EXCESSIVE_DEFER;
value |= (max_retransmissions << HALFDUP_MAX_RETRANSMISSION_SHIFT);
value |=
((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT) &
IPGIFG_NBTB_CS_IPG_MASK);
value |=
((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) &
IPGIFG_NBTB_IPG_MASK);
value |=
((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) &
IPGIFG_MIN_IFG_MASK);
value |= (btb_ipg & IPGIFG_BTB_IPG_MASK);
out_be32(ipgifg_register, value); return 0;
}
int init_flow_control_params(u32 automatic_flow_control_mode, int rx_flow_control_enable, int tx_flow_control_enable,
u16 pause_period,
u16 extension_field,
u32 __iomem *upsmr_register,
u32 __iomem *uempr_register,
u32 __iomem *maccfg1_register)
{
u32 value = 0;
/* Set UEMPR register */
value = (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT;
value |= (u32) extension_field << UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT;
out_be32(uempr_register, value);
/* Set UPSMR register */
setbits32(upsmr_register, automatic_flow_control_mode);
value = in_be32(maccfg1_register); if (rx_flow_control_enable)
value |= MACCFG1_FLOW_RX; if (tx_flow_control_enable)
value |= MACCFG1_FLOW_TX;
out_be32(maccfg1_register, value);
/* Enable hardware statistics gathering if requested */ if (enable_hardware_statistics)
setbits32(upsmr_register, UCC_GETH_UPSMR_HSE);
/* Clear hardware statistics counters */
uescr_value = in_be16(uescr_register);
uescr_value |= UESCR_CLRCNT; /* Automatically zero hardware statistics counters on read,
if requested */ if (auto_zero_hardware_statistics)
uescr_value |= UESCR_AUTOZ;
out_be16(uescr_register, uescr_value);
return 0;
}
staticint init_firmware_statistics_gathering_mode(int
enable_tx_firmware_statistics, int enable_rx_firmware_statistics,
u32 __iomem *tx_rmon_base_ptr,
u32 tx_firmware_statistics_structure_address,
u32 __iomem *rx_rmon_base_ptr,
u32 rx_firmware_statistics_structure_address,
u16 __iomem *temoder_register,
u32 __iomem *remoder_register)
{ /* Note: this function does not check if */ /* the parameters it receives are NULL */
if (enable_tx_firmware_statistics) {
out_be32(tx_rmon_base_ptr,
tx_firmware_statistics_structure_address);
setbits16(temoder_register, TEMODER_TX_RMON_STATISTICS_ENABLE);
}
if (enable_rx_firmware_statistics) {
out_be32(rx_rmon_base_ptr,
rx_firmware_statistics_structure_address);
setbits32(remoder_register, REMODER_RX_RMON_STATISTICS_ENABLE);
}
/* Example: for a station address of 0x12345678ABCD, */ /* 0x12 is byte 0, 0x34 is byte 1 and so on and 0xCD is byte 5 */
/* MACSTNADDR1 Register: */
/* 0 7 8 15 */ /* station address byte 5 station address byte 4 */ /* 16 23 24 31 */ /* station address byte 3 station address byte 2 */
value |= (u32) ((address_byte_2 << 0) & 0x000000FF);
value |= (u32) ((address_byte_3 << 8) & 0x0000FF00);
value |= (u32) ((address_byte_4 << 16) & 0x00FF0000);
value |= (u32) ((address_byte_5 << 24) & 0xFF000000);
out_be32(macstnaddr1_register, value);
/* MACSTNADDR2 Register: */
/* 0 7 8 15 */ /* station address byte 1 station address byte 0 */ /* 16 23 24 31 */ /* reserved reserved */
value = 0;
value |= (u32) ((address_byte_0 << 16) & 0x00FF0000);
value |= (u32) ((address_byte_1 << 24) & 0xFF000000);
out_be32(macstnaddr2_register, value);
return 0;
}
staticint init_rx_parameters(int reject_broadcast, int receive_short_frames, int promiscuous, u32 __iomem *upsmr_register)
{
u32 value = 0;
value = in_be32(upsmr_register);
if (reject_broadcast)
value |= UCC_GETH_UPSMR_BRO; else
value &= ~UCC_GETH_UPSMR_BRO;
if (receive_short_frames)
value |= UCC_GETH_UPSMR_RSH; else
value &= ~UCC_GETH_UPSMR_RSH;
if (promiscuous)
value |= UCC_GETH_UPSMR_PRO; else
value &= ~UCC_GETH_UPSMR_PRO;
out_be32(upsmr_register, value);
return 0;
}
staticint init_max_rx_buff_len(u16 max_rx_buf_len,
u16 __iomem *mrblr_register)
{ /* max_rx_buf_len value must be a multiple of 128 */ if ((max_rx_buf_len == 0) ||
(max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT)) return -EINVAL;
/* Keep issuing command and checking acknowledge bit until
it is asserted, according to spec */ do { /* Issue host command */
cecr_subblock =
ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.
ucc_num);
qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
QE_CR_PROTOCOL_ETHERNET, 0);
msleep(10);
temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack);
} while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i);
/* check if the UCC number is in range. */ if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { if (netif_msg_probe(ugeth))
pr_err("ucc_num out of range\n"); return -EINVAL;
}
/* Get Tx and Rx going again, in case this channel was actively
disabled. */ if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx)
ugeth_restart_tx(ugeth); if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx)
ugeth_restart_rx(ugeth);
ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */
/* check if the UCC number is in range. */ if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { if (netif_msg_probe(ugeth))
pr_err("ucc_num out of range\n"); return -EINVAL;
}
/* Stop any transmissions */ if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx)
ugeth_graceful_stop_tx(ugeth);
/* Stop any receptions */ if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx)
ugeth_graceful_stop_rx(ugeth);
ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */
return 0;
}
staticvoid ugeth_quiesce(struct ucc_geth_private *ugeth)
{ /* Prevent any further xmits */
netif_tx_stop_all_queues(ugeth->ndev);
/* Disable the interrupt to avoid NAPI rescheduling. */
disable_irq(ugeth->ug_info->uf_info.irq);
/* Stop NAPI, and possibly wait for its completion. */
napi_disable(&ugeth->napi);
}
/* allow to xmit again */
netif_tx_wake_all_queues(ugeth->ndev);
netdev_watchdog_up(ugeth->ndev);
}
/* Initialize TBI PHY interface for communicating with the * SERDES lynx PHY on the chip. We communicate with this PHY * through the MDIO bus on each controller, treating it as a * "normal" PHY at the address found in the UTBIPA register. We assume * that the UTBIPA register is valid. Either the MDIO bus code will set * it to a value that doesn't conflict with other PHYs on the bus, or the * value doesn't matter, as there are no other PHYs on the bus.
*/ staticvoid uec_configure_serdes(struct net_device *dev)
{ struct ucc_geth_private *ugeth = netdev_priv(dev); struct ucc_geth_info *ug_info = ugeth->ug_info; struct phy_device *tbiphy;
if (!ug_info->tbi_node) {
dev_warn(&dev->dev, "SGMII mode requires that the device tree specify a tbi-handle\n"); return;
}
tbiphy = of_phy_find_device(ug_info->tbi_node); if (!tbiphy) {
dev_err(&dev->dev, "error: Could not get TBI device\n"); return;
}
/* * If the link is already up, we must already be ok, and don't need to * configure and reset the TBI<->SerDes link. Maybe U-Boot configured * everything for us? Resetting it takes the link down and requires * several seconds for it to come back.
*/ if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) {
put_device(&tbiphy->mdio.dev); return;
}
/* Single clk mode, mii mode off(for serdes communication) */
phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS);
if (maccfg2 != old_maccfg2 || upsmr != old_upsmr) { /* * To change the MAC configuration we need to disable * the controller. To do so, we have to either grab * ugeth->lock, which is a bad idea since 'graceful * stop' commands might take quite a while, or we can * quiesce driver's activity.
*/
ugeth_quiesce(ugeth);
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
comm_dir = 0; if (uccf->enabled_tx)
comm_dir |= COMM_DIR_TX; if (uccf->enabled_rx)
comm_dir |= COMM_DIR_RX; if (comm_dir)
ugeth_disable(ugeth, comm_dir);
/* Clear the hash table. */
out_be32(addr_h, 0x00000000);
out_be32(addr_l, 0x00000000);
if (!p_lh) return 0;
num = *p_counter;
/* Delete all remaining CQ elements */ for (i = 0; i < num; i++)
put_enet_addr_container(ENET_ADDR_CONT_ENTRY(dequeue(p_lh)));
*p_counter = 0;
if (comm_dir)
ugeth_enable(ugeth, comm_dir);
return 0;
}
staticint ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth,
u8 paddr_num)
{
ugeth->indAddrRegUsed[paddr_num] = 0; /* mark this paddr as not used */ return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */
}
if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the * filter to all 1's.
*/
out_be32(&p_82xx_addr_filt->gaddr_h, 0xffffffff);
out_be32(&p_82xx_addr_filt->gaddr_l, 0xffffffff);
} else { /* Clear filter and add the addresses in the list.
*/
out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
netdev_for_each_mc_addr(ha, dev) { /* Ask CPM to run CRC and set bit in * filter mask.
*/
hw_add_addr_in_hash(ugeth, ha->addr);
}
}
}
}
/* Rx BD lengths */ for (i = 0; i < ucc_geth_rx_queues(ug_info); i++) { if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) ||
(ug_info->bdRingLenRx[i] %
UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) { if (netif_msg_probe(ugeth))
pr_err("Rx BD ring length must be multiple of 4, no smaller than 8\n"); return -EINVAL;
}
}
/* Tx BD lengths */ for (i = 0; i < ucc_geth_tx_queues(ug_info); i++) { if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) { if (netif_msg_probe(ugeth))
pr_err("Tx BD ring length must be no smaller than 2\n"); return -EINVAL;
}
}
/* mrblr */ if ((uf_info->max_rx_buf_length == 0) ||
(uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) { if (netif_msg_probe(ugeth))
pr_err("max_rx_buf_length must be non-zero multiple of 128\n"); return -EINVAL;
}
/* num Tx queues */ if (ucc_geth_tx_queues(ug_info) > NUM_TX_QUEUES) { if (netif_msg_probe(ugeth))
pr_err("number of tx queues too large\n"); return -EINVAL;
}
/* num Rx queues */ if (ucc_geth_rx_queues(ug_info) > NUM_RX_QUEUES) { if (netif_msg_probe(ugeth))
pr_err("number of rx queues too large\n"); return -EINVAL;
}
/* l2qt */ for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) { if (ug_info->l2qt[i] >= ucc_geth_rx_queues(ug_info)) { if (netif_msg_probe(ugeth))
pr_err("VLAN priority table entry must not be larger than number of Rx queues\n"); return -EINVAL;
}
}
/* l3qt */ for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) { if (ug_info->l3qt[i] >= ucc_geth_rx_queues(ug_info)) { if (netif_msg_probe(ugeth))
pr_err("IP priority table entry must not be larger than number of Rx queues\n"); return -EINVAL;
}
}
if (ug_info->cam && !ug_info->ecamptr) { if (netif_msg_probe(ugeth))
pr_err("If cam mode is chosen, must supply cam ptr\n"); return -EINVAL;
}
if ((ug_info->numStationAddresses !=
UCC_GETH_NUM_OF_STATION_ADDRESSES_1) &&
ug_info->rxExtendedFiltering) { if (netif_msg_probe(ugeth))
pr_err("Number of station addresses greater than 1 not allowed in extended parsing mode\n"); return -EINVAL;
}
/* Generate uccm_mask for receive */
uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */ for (i = 0; i < ucc_geth_rx_queues(ug_info); i++)
uf_info->uccm_mask |= (UCC_GETH_UCCE_RXF0 << i);
for (i = 0; i < ucc_geth_tx_queues(ug_info); i++)
uf_info->uccm_mask |= (UCC_GETH_UCCE_TXB0 << i); /* Initialize the general fast UCC block. */ if (ucc_fast_init(uf_info, &ugeth->uccf)) { if (netif_msg_probe(ugeth))
pr_err("Failed to init uccf\n"); return -ENOMEM;
}
/* read the number of risc engines, update the riscTx and riscRx * if there are 4 riscs in QE
*/ if (qe_get_num_of_risc() == 4) {
ug_info->riscTx = QE_RISC_ALLOCATION_FOUR_RISCS;
ug_info->riscRx = QE_RISC_ALLOCATION_FOUR_RISCS;
}
ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs)); if (!ugeth->ug_regs) { if (netif_msg_probe(ugeth))
pr_err("Failed to ioremap regs\n"); return -ENOMEM;
}
return 0;
}
staticint ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)
{ struct ucc_geth_info *ug_info; struct ucc_fast_info *uf_info; int length;
u16 i, j;
u8 __iomem *bd;
if (!ugeth->p_tx_bd_ring[j]) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate memory for Tx bd rings\n"); return -ENOMEM;
} /* Zero unused end of bd ring, according to spec */
memset(ugeth->p_tx_bd_ring[j] + length, 0, alloc - length);
}
numThreadsRxNumerical = ucc_geth_thread_count(ug_info->numThreadsRx); if (!numThreadsRxNumerical) { if (netif_msg_ifup(ugeth))
pr_err("Bad number of Rx threads value\n"); return -EINVAL;
}
numThreadsTxNumerical = ucc_geth_thread_count(ug_info->numThreadsTx); if (!numThreadsTxNumerical) { if (netif_msg_ifup(ugeth))
pr_err("Bad number of Tx threads value\n"); return -EINVAL;
}
/* Set UPSMR */ /* For more details see the hardware spec. */
init_rx_parameters(ug_info->bro,
ug_info->rsh, ug_info->pro, &uf_regs->upsmr);
/* We're going to ignore other registers for now, */ /* except as needed to get up and running */
/* Set MACCFG1 */ /* For more details see the hardware spec. */
init_flow_control_params(ug_info->aufc,
ug_info->receiveFlowControl,
ug_info->transmitFlowControl,
ug_info->pausePeriod,
ug_info->extensionField,
&uf_regs->upsmr,
&ug_regs->uempr, &ug_regs->maccfg1);
/* Set IPGIFG */ /* For more details see the hardware spec. */
ret_val = init_inter_frame_gap_params(ug_info->nonBackToBackIfgPart1,
ug_info->nonBackToBackIfgPart2,
ug_info->
miminumInterFrameGapEnforcement,
ug_info->backToBackInterFrameGap,
&ug_regs->ipgifg); if (ret_val != 0) { if (netif_msg_ifup(ugeth))
pr_err("IPGIFG initialization parameter too large\n"); return ret_val;
}
/* Set HAFDUP */ /* For more details see the hardware spec. */
ret_val = init_half_duplex_params(ug_info->altBeb,
ug_info->backPressureNoBackoff,
ug_info->noBackoff,
ug_info->excessDefer,
ug_info->altBebTruncation,
ug_info->maxRetransmission,
ug_info->collisionWindow,
&ug_regs->hafdup); if (ret_val != 0) { if (netif_msg_ifup(ugeth))
pr_err("Half Duplex initialization parameter too large\n"); return ret_val;
}
/* Set IFSTAT */ /* For more details see the hardware spec. */ /* Read only - resets upon read */
ifstat = in_be32(&ug_regs->ifstat);
/* Clear UEMPR */ /* For more details see the hardware spec. */
out_be32(&ug_regs->uempr, 0);
/* Set UESCR */ /* For more details see the hardware spec. */
init_hw_statistics_gathering_mode((ug_info->statisticsMode &
UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE),
0, &uf_regs->upsmr, &ug_regs->uescr);
ret_val = ucc_geth_alloc_tx(ugeth); if (ret_val != 0) return ret_val;
ret_val = ucc_geth_alloc_rx(ugeth); if (ret_val != 0) return ret_val;
/* * Global PRAM
*/ /* Tx global PRAM */ /* Allocate global tx parameter RAM page */
tx_glbl_pram_offset =
qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram),
UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT); if (tx_glbl_pram_offset < 0) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_tx_glbl_pram\n"); return -ENOMEM;
}
ugeth->p_tx_glbl_pram = qe_muram_addr(tx_glbl_pram_offset); /* Fill global PRAM */
/* TQPTR */ /* Size varies with number of Tx threads */
ugeth->thread_dat_tx_offset =
qe_muram_alloc(numThreadsTxNumerical * sizeof(struct ucc_geth_thread_data_tx) +
32 * (numThreadsTxNumerical == 1),
UCC_GETH_THREAD_DATA_ALIGNMENT); if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_thread_data_tx\n"); return -ENOMEM;
}
/* vtagtable */ for (i = 0; i < UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX; i++)
out_be32(&ugeth->p_tx_glbl_pram->vtagtable[i],
ug_info->vtagtable[i]);
/* iphoffset */ for (i = 0; i < TX_IP_OFFSET_ENTRY_MAX; i++)
out_8(&ugeth->p_tx_glbl_pram->iphoffset[i],
ug_info->iphoffset[i]);
/* SQPTR */ /* Size varies with number of Tx queues */
ugeth->send_q_mem_reg_offset =
qe_muram_alloc(ucc_geth_tx_queues(ug_info) * sizeof(struct ucc_geth_send_queue_qd),
UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_send_q_mem_reg\n"); return -ENOMEM;
}
/* Setup the table */ /* Assume BD rings are already established */ for (i = 0; i < ucc_geth_tx_queues(ug_info); i++) {
endOfRing =
ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] -
1) * sizeof(struct qe_bd);
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
(u32) virt_to_phys(ugeth->p_tx_bd_ring[i]));
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
last_bd_completed_address,
(u32) virt_to_phys(endOfRing));
}
/* schedulerbasepointer */
if (ucc_geth_tx_queues(ug_info) > 1) { /* scheduler exists only if more than 1 tx queue */
ugeth->scheduler_offset =
qe_muram_alloc(sizeof(struct ucc_geth_scheduler),
UCC_GETH_SCHEDULER_ALIGNMENT); if (IS_ERR_VALUE(ugeth->scheduler_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_scheduler\n"); return -ENOMEM;
}
/* Function code register value to be used later */
function_code = UCC_BMR_BO_BE | UCC_BMR_GBL; /* Required for QE */
/* function code register */
out_be32(&ugeth->p_tx_glbl_pram->tstate, ((u32) function_code) << 24);
/* Rx global PRAM */ /* Allocate global rx parameter RAM page */
rx_glbl_pram_offset =
qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram),
UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT); if (rx_glbl_pram_offset < 0) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_rx_glbl_pram\n"); return -ENOMEM;
}
ugeth->p_rx_glbl_pram = qe_muram_addr(rx_glbl_pram_offset); /* Fill global PRAM */
/* RQPTR */ /* Size varies with number of Rx threads */
ugeth->thread_dat_rx_offset =
qe_muram_alloc(numThreadsRxNumerical * sizeof(struct ucc_geth_thread_data_rx),
UCC_GETH_THREAD_DATA_ALIGNMENT); if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_thread_data_rx\n"); return -ENOMEM;
}
/* rxrmonbaseptr (statistics) */ if (ug_info->
statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
ugeth->rx_fw_statistics_pram_offset =
qe_muram_alloc(sizeof
(struct ucc_geth_rx_firmware_statistics_pram),
UCC_GETH_RX_STATISTICS_ALIGNMENT); if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_rx_fw_statistics_pram\n"); return -ENOMEM;
}
ugeth->p_rx_fw_statistics_pram =
(struct ucc_geth_rx_firmware_statistics_pram __iomem *)
qe_muram_addr(ugeth->rx_fw_statistics_pram_offset);
}
/* intCoalescingPtr */
/* Size varies with number of Rx queues */
ugeth->rx_irq_coalescing_tbl_offset =
qe_muram_alloc(ucc_geth_rx_queues(ug_info) * sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+ 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_rx_irq_coalescing_tbl\n"); return -ENOMEM;
}
/* Setup the table */ /* Assume BD rings are already established */ for (i = 0; i < ucc_geth_rx_queues(ug_info); i++) {
out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
(u32) virt_to_phys(ugeth->p_rx_bd_ring[i])); /* rest of fields handled by QE */
}
/* remoder */ /* Already has speed set */
if (ugeth->rx_extended_features)
remoder |= REMODER_RX_EXTENDED_FEATURES; if (ug_info->rxExtendedFiltering)
remoder |= REMODER_RX_EXTENDED_FILTERING; if (ug_info->dynamicMaxFrameLength)
remoder |= REMODER_DYNAMIC_MAX_FRAME_LENGTH; if (ug_info->dynamicMinFrameLength)
remoder |= REMODER_DYNAMIC_MIN_FRAME_LENGTH;
remoder |=
ug_info->vlanOperationTagged << REMODER_VLAN_OPERATION_TAGGED_SHIFT;
remoder |=
ug_info->
vlanOperationNonTagged << REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT;
remoder |= ug_info->rxQoSMode << REMODER_RX_QOS_MODE_SHIFT;
remoder |= ((ucc_geth_rx_queues(ug_info) - 1) << REMODER_NUM_OF_QUEUES_SHIFT); if (ug_info->ipCheckSumCheck)
remoder |= REMODER_IP_CHECKSUM_CHECK; if (ug_info->ipAddressAlignment)
remoder |= REMODER_IP_ADDRESS_ALIGNMENT;
out_be32(&ugeth->p_rx_glbl_pram->remoder, remoder);
/* Note that this function must be called */ /* ONLY AFTER p_tx_fw_statistics_pram */ /* andp_UccGethRxFirmwareStatisticsPram are allocated ! */
init_firmware_statistics_gathering_mode((ug_info->
statisticsMode &
UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX),
(ug_info->statisticsMode &
UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX),
&ugeth->p_tx_glbl_pram->txrmonbaseptr,
ugeth->tx_fw_statistics_pram_offset,
&ugeth->p_rx_glbl_pram->rxrmonbaseptr,
ugeth->rx_fw_statistics_pram_offset,
&ugeth->p_tx_glbl_pram->temoder,
&ugeth->p_rx_glbl_pram->remoder);
/* function code register */
out_8(&ugeth->p_rx_glbl_pram->rstate, function_code);
/* initialize extended filtering */ if (ug_info->rxExtendedFiltering) { if (!ug_info->extendedFilteringChainPointer) { if (netif_msg_ifup(ugeth))
pr_err("Null Extended Filtering Chain Pointer\n"); return -EINVAL;
}
/* Allocate memory for extended filtering Mode Global
Parameters */
ugeth->exf_glbl_param_offset =
qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram),
UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT); if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_exf_glbl_param\n"); return -ENOMEM;
}
/* Allocate shadow InitEnet command parameter structure. * This is needed because after the InitEnet command is executed, * the structure in DPRAM is released, because DPRAM is a premium * resource. * This shadow structure keeps a copy of what was done so that the * allocated resources can be released when the channel is freed.
*/ if (!(ugeth->p_init_enet_param_shadow =
kzalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate memory for p_UccInitEnetParamShadows\n"); return -ENOMEM;
}
/* Fill shadow InitEnet command parameter structure */
ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=
rx_glbl_pram_offset | ug_info->riscRx; if ((ug_info->largestexternallookupkeysize !=
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) &&
(ug_info->largestexternallookupkeysize !=
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) &&
(ug_info->largestexternallookupkeysize !=
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { if (netif_msg_ifup(ugeth))
pr_err("Invalid largest External Lookup Key Size\n"); return -EINVAL;
}
ugeth->p_init_enet_param_shadow->largestexternallookupkeysize =
ug_info->largestexternallookupkeysize;
size = sizeof(struct ucc_geth_thread_rx_pram); if (ug_info->rxExtendedFiltering) {
size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; if (ug_info->largestexternallookupkeysize ==
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
size +=
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; if (ug_info->largestexternallookupkeysize ==
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)
size +=
THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16;
}
if ((ret_val = fill_init_enet_entries(ugeth, &(ugeth->
p_init_enet_param_shadow->rxthread[0]),
(u8) (numThreadsRxNumerical + 1) /* Rx needs one extra for terminator */
, size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT,
ug_info->riscRx, 1)) != 0) { if (netif_msg_ifup(ugeth))
pr_err("Can not fill p_init_enet_param_shadow\n"); return ret_val;
}
ugeth->p_init_enet_param_shadow->txglobal =
tx_glbl_pram_offset | ug_info->riscTx; if ((ret_val =
fill_init_enet_entries(ugeth,
&(ugeth->p_init_enet_param_shadow->
txthread[0]), numThreadsTxNumerical, sizeof(struct ucc_geth_thread_tx_pram),
UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
ug_info->riscTx, 0)) != 0) { if (netif_msg_ifup(ugeth))
pr_err("Can not fill p_init_enet_param_shadow\n"); return ret_val;
}
/* Load Rx bds with buffers */ for (i = 0; i < ucc_geth_rx_queues(ug_info); i++) { if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) { if (netif_msg_ifup(ugeth))
pr_err("Can not fill Rx bds with buffers\n"); return ret_val;
}
}
/* Allocate InitEnet command parameter structure */
init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4); if (IS_ERR_VALUE(init_enet_pram_offset)) { if (netif_msg_ifup(ugeth))
pr_err("Can not allocate DPRAM memory for p_init_enet_pram\n"); return -ENOMEM;
}
p_init_enet_pram =
(struct ucc_geth_init_pram __iomem *) qe_muram_addr(init_enet_pram_offset);
/* Copy shadow InitEnet command parameter structure into PRAM */
out_8(&p_init_enet_pram->resinit1,
ugeth->p_init_enet_param_shadow->resinit1);
out_8(&p_init_enet_pram->resinit2,
ugeth->p_init_enet_param_shadow->resinit2);
out_8(&p_init_enet_pram->resinit3,
ugeth->p_init_enet_param_shadow->resinit3);
out_8(&p_init_enet_pram->resinit4,
ugeth->p_init_enet_param_shadow->resinit4);
out_be16(&p_init_enet_pram->resinit5,
ugeth->p_init_enet_param_shadow->resinit5);
out_8(&p_init_enet_pram->largestexternallookupkeysize,
ugeth->p_init_enet_param_shadow->largestexternallookupkeysize);
out_be32(&p_init_enet_pram->rgftgfrxglobal,
ugeth->p_init_enet_param_shadow->rgftgfrxglobal); for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++)
out_be32(&p_init_enet_pram->rxthread[i],
ugeth->p_init_enet_param_shadow->rxthread[i]);
out_be32(&p_init_enet_pram->txglobal,
ugeth->p_init_enet_param_shadow->txglobal); for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_TX; i++)
out_be32(&p_init_enet_pram->txthread[i],
ugeth->p_init_enet_param_shadow->txthread[i]);
/* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ static netdev_tx_t
ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ struct ucc_geth_private *ugeth = netdev_priv(dev); #ifdef CONFIG_UGETH_TX_ON_DEMAND struct ucc_fast_private *uccf; #endif
u8 __iomem *bd; /* BD pointer */
u32 bd_status;
u8 txQ = 0; unsignedlong flags;
/* Start from the next BD that should be filled */
bd = ugeth->txBd[txQ];
bd_status = in_be32((u32 __iomem *)bd); /* Save the skb pointer so we can free it later */
ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb;
/* Update the current skb pointer (wrapping if this was the last) */
ugeth->skb_curtx[txQ] =
(ugeth->skb_curtx[txQ] +
1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
/* set up the buffer descriptor */
out_be32(&((struct qe_bd __iomem *)bd)->buf,
dma_map_single(ugeth->dev, skb->data,
skb->len, DMA_TO_DEVICE));
/* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
/* set bd status and length */
out_be32((u32 __iomem *)bd, bd_status);
/* Move to next BD in the ring */ if (!(bd_status & T_W))
bd += sizeof(struct qe_bd); else
bd = ugeth->p_tx_bd_ring[txQ];
/* If the next BD still needs to be cleaned up, then the bds
are full. We need to tell the kernel to stop sending us stuff. */ if (bd == ugeth->confBd[txQ]) { if (!netif_queue_stopped(dev))
netif_stop_queue(dev);
}
ugeth->txBd[txQ] = bd;
skb_tx_timestamp(skb);
if (ugeth->p_scheduler) {
ugeth->cpucount[txQ]++; /* Indicate to QE that there are more Tx bds ready for
transmission */ /* This is done by writing a running counter of the bd
count to the scheduler PRAM. */
out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
}
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
bd_status = in_be32((u32 __iomem *)bd);
/* while there are received buffers and BD is full (~R_E) */ while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) {
bdBuffer = (u8 *) in_be32(&((struct qe_bd __iomem *)bd)->buf);
length = (u16) ((bd_status & BD_LENGTH_MASK) - 4);
skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]];
/* determine whether buffer is first, last, first and last
(single buffer frame) or middle (not first and not last) */ if (!skb ||
(!(bd_status & (R_F | R_L))) ||
(bd_status & R_ERRORS_FATAL)) { if (netif_msg_rx_err(ugeth))
pr_err("%d: ERROR!!! skb - 0x%08x\n",
__LINE__, (u32)skb);
dev_kfree_skb(skb);
/* check for receive events that require processing */ if (ucce & (UCCE_RX_EVENTS | UCCE_TX_EVENTS)) { if (napi_schedule_prep(&ugeth->napi)) {
uccm &= ~(UCCE_RX_EVENTS | UCCE_TX_EVENTS);
out_be32(uccf->p_uccm, uccm);
__napi_schedule(&ugeth->napi);
}
}
/* Errors and other events */ if (ucce & UCCE_OTHER) { if (ucce & UCC_GETH_UCCE_BSY)
dev->stats.rx_errors++; if (ucce & UCC_GETH_UCCE_TXE)
dev->stats.tx_errors++;
}
return IRQ_HANDLED;
}
#ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing.
*/ staticvoid ucc_netpoll(struct net_device *dev)
{ struct ucc_geth_private *ugeth = netdev_priv(dev); int irq = ugeth->ug_info->uf_info.irq;
err = ucc_geth_startup(ugeth); if (err) {
netif_err(ugeth, ifup, dev, "Cannot configure net device, aborting\n"); goto err;
}
/* Set MACSTNADDR1, MACSTNADDR2 */ /* For more details see the hardware spec. */
init_mac_station_addr_regs(dev->dev_addr[0],
dev->dev_addr[1],
dev->dev_addr[2],
dev->dev_addr[3],
dev->dev_addr[4],
dev->dev_addr[5],
&ugeth->ug_regs->macstnaddr1,
&ugeth->ug_regs->macstnaddr2);
/* Called when something needs to use the ethernet device */ /* Returns 0 for success. */ staticint ucc_geth_open(struct net_device *dev)
{ struct ucc_geth_private *ugeth = netdev_priv(dev); int err;
ugeth_vdbg("%s: IN", __func__);
/* Test station address */ if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
netif_err(ugeth, ifup, dev, "Multicast address used for station address - is this what you wanted?\n"); return -EINVAL;
}
err = phylink_of_phy_connect(ugeth->phylink, ugeth->dev->of_node, 0); if (err) {
dev_err(&dev->dev, "Could not attach to PHY\n"); return -ENODEV;
}
/* Reopen device. This will reset the MAC and PHY. */ staticvoid ucc_geth_timeout_work(struct work_struct *work)
{ struct ucc_geth_private *ugeth; struct net_device *dev;
ugeth = container_of(work, struct ucc_geth_private, timeout_work);
dev = ugeth->ndev;
ugeth_vdbg("%s: IN", __func__);
dev->stats.tx_errors++;
ugeth_dump_regs(ugeth);
if (dev->flags & IFF_UP) { /* * Must reset MAC *and* PHY. This is done by reopening * the device.
*/
netif_tx_stop_all_queues(dev);
ucc_geth_stop(ugeth);
ucc_geth_init_mac(ugeth); /* Must start PHY here */
phylink_start(ugeth->phylink);
netif_tx_start_all_queues(dev);
}
netif_tx_schedule_all(dev);
}
/* * ucc_geth_timeout gets called when a packet has not been * transmitted after a set amount of time.
*/ staticvoid ucc_geth_timeout(struct net_device *dev, unsignedint txqueue)
{ struct ucc_geth_private *ugeth = netdev_priv(dev);
if (qe_alive_during_sleep()) { if (ugeth->wol_en & WAKE_MAGIC) {
ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX);
clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
}
ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
} else { /* * Full reinitialization is required if QE shuts down * during sleep.
*/
ucc_geth_memclean(ugeth);
/* If QE's snum number is 46/76 which means we need to support * 4 UECs at 1000Base-T simultaneously, we need to allocate * more Threads to Rx.
*/ if ((snums == 76) || (snums == 46))
ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_6; else
ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4;
}
if (netif_msg_probe(&debug))
pr_info("UCC%1d at 0x%8llx (irq = %d)\n",
ug_info->uf_info.ucc_num + 1,
(u64)ug_info->uf_info.regs,
ug_info->uf_info.irq);
/* Create an ethernet device instance */
dev = devm_alloc_etherdev(&ofdev->dev, sizeof(*ugeth)); if (!dev) {
err = -ENOMEM; goto err_put_tbi;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.