···11+config FS_ENET22+ tristate "Freescale Ethernet Driver"33+ depends on NET_ETHERNET && (CPM1 || CPM2)44+ select MII55+66+config FS_ENET_HAS_SCC77+ bool "Chip has an SCC usable for ethernet"88+ depends on FS_ENET && (CPM1 || CPM2)99+ default y1010+1111+config FS_ENET_HAS_FCC1212+ bool "Chip has an FCC usable for ethernet"1313+ depends on FS_ENET && CPM21414+ default y1515+1616+config FS_ENET_HAS_FEC1717+ bool "Chip has an FEC usable for ethernet"1818+ depends on FS_ENET && CPM11919+ default y2020+
+10
drivers/net/fs_enet/Makefile
···11+#22+# Makefile for the Freescale Ethernet controllers33+#44+55+obj-$(CONFIG_FS_ENET) += fs_enet.o66+77+obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o88+obj-$(CONFIG_8260) += mac-fcc.o99+1010+fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o
+1226
drivers/net/fs_enet/fs_enet-main.c
···11+/*22+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.33+ *44+ * Copyright (c) 2003 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ * 77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>1111+ * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>1212+ *1313+ * This file is licensed under the terms of the GNU General Public License 1414+ * version 2. This program is licensed "as is" without any warranty of any 1515+ * kind, whether express or implied.1616+ */1717+1818+#include <linux/config.h>1919+#include <linux/module.h>2020+#include <linux/kernel.h>2121+#include <linux/types.h>2222+#include <linux/sched.h>2323+#include <linux/string.h>2424+#include <linux/ptrace.h>2525+#include <linux/errno.h>2626+#include <linux/ioport.h>2727+#include <linux/slab.h>2828+#include <linux/interrupt.h>2929+#include <linux/pci.h>3030+#include <linux/init.h>3131+#include <linux/delay.h>3232+#include <linux/netdevice.h>3333+#include <linux/etherdevice.h>3434+#include <linux/skbuff.h>3535+#include <linux/spinlock.h>3636+#include <linux/mii.h>3737+#include <linux/ethtool.h>3838+#include <linux/bitops.h>3939+#include <linux/fs.h>4040+4141+#include <linux/vmalloc.h>4242+#include <asm/pgtable.h>4343+4444+#include <asm/pgtable.h>4545+#include <asm/irq.h>4646+#include <asm/uaccess.h>4747+4848+#include "fs_enet.h"4949+5050+/*************************************************/5151+5252+static char version[] __devinitdata =5353+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";5454+5555+MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");5656+MODULE_DESCRIPTION("Freescale Ethernet Driver");5757+MODULE_LICENSE("GPL");5858+MODULE_VERSION(DRV_MODULE_VERSION);5959+6060+MODULE_PARM(fs_enet_debug, "i");6161+MODULE_PARM_DESC(fs_enet_debug,6262+ "Freescale bitmapped debugging message enable value");6363+6464+int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */6565+6666+static void fs_set_multicast_list(struct net_device *dev)6767+{6868+ struct fs_enet_private *fep = netdev_priv(dev);6969+7070+ (*fep->ops->set_multicast_list)(dev);7171+}7272+7373+/* NAPI receive function */7474+static int fs_enet_rx_napi(struct net_device *dev, int *budget)7575+{7676+ struct fs_enet_private *fep = netdev_priv(dev);7777+ const struct fs_platform_info *fpi = fep->fpi;7878+ cbd_t *bdp;7979+ struct sk_buff *skb, *skbn, *skbt;8080+ int received = 0;8181+ u16 pkt_len, sc;8282+ int curidx;8383+ int rx_work_limit = 0; /* pacify gcc */8484+8585+ rx_work_limit = min(dev->quota, *budget);8686+8787+ if (!netif_running(dev))8888+ return 0;8989+9090+ /*9191+ * First, grab all of the stats for the incoming packet.9292+ * These get messed up if we get called due to a busy condition.9393+ */9494+ bdp = fep->cur_rx;9595+9696+ /* clear RX status bits for napi*/9797+ (*fep->ops->napi_clear_rx_event)(dev);9898+9999+ while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {100100+101101+ curidx = bdp - fep->rx_bd_base;102102+103103+ /*104104+ * Since we have allocated space to hold a complete frame,105105+ * the last indicator should be set.106106+ */107107+ if ((sc & BD_ENET_RX_LAST) == 0)108108+ printk(KERN_WARNING DRV_MODULE_NAME109109+ ": %s rcv is not +last\n",110110+ dev->name);111111+112112+ /*113113+ * Check for errors. 114114+ */115115+ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |116116+ BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {117117+ fep->stats.rx_errors++;118118+ /* Frame too long or too short. */119119+ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))120120+ fep->stats.rx_length_errors++;121121+ /* Frame alignment */122122+ if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL))123123+ fep->stats.rx_frame_errors++;124124+ /* CRC Error */125125+ if (sc & BD_ENET_RX_CR)126126+ fep->stats.rx_crc_errors++;127127+ /* FIFO overrun */128128+ if (sc & BD_ENET_RX_OV)129129+ fep->stats.rx_crc_errors++;130130+131131+ skb = fep->rx_skbuff[curidx];132132+133133+ dma_unmap_single(fep->dev, skb->data,134134+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),135135+ DMA_FROM_DEVICE);136136+137137+ skbn = skb;138138+139139+ } else {140140+141141+ /* napi, got packet but no quota */142142+ if (--rx_work_limit < 0)143143+ break;144144+145145+ skb = fep->rx_skbuff[curidx];146146+147147+ dma_unmap_single(fep->dev, skb->data,148148+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),149149+ DMA_FROM_DEVICE);150150+151151+ /*152152+ * Process the incoming frame.153153+ */154154+ fep->stats.rx_packets++;155155+ pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */156156+ fep->stats.rx_bytes += pkt_len + 4;157157+158158+ if (pkt_len <= fpi->rx_copybreak) {159159+ /* +2 to make IP header L1 cache aligned */160160+ skbn = dev_alloc_skb(pkt_len + 2);161161+ if (skbn != NULL) {162162+ skb_reserve(skbn, 2); /* align IP header */163163+ memcpy(skbn->data, skb->data, pkt_len);164164+ /* swap */165165+ skbt = skb;166166+ skb = skbn;167167+ skbn = skbt;168168+ }169169+ } else170170+ skbn = dev_alloc_skb(ENET_RX_FRSIZE);171171+172172+ if (skbn != NULL) {173173+ skb->dev = dev;174174+ skb_put(skb, pkt_len); /* Make room */175175+ skb->protocol = eth_type_trans(skb, dev);176176+ received++;177177+ netif_receive_skb(skb);178178+ } else {179179+ printk(KERN_WARNING DRV_MODULE_NAME180180+ ": %s Memory squeeze, dropping packet.\n",181181+ dev->name);182182+ fep->stats.rx_dropped++;183183+ skbn = skb;184184+ }185185+ }186186+187187+ fep->rx_skbuff[curidx] = skbn;188188+ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data,189189+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),190190+ DMA_FROM_DEVICE));191191+ CBDW_DATLEN(bdp, 0);192192+ CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);193193+194194+ /*195195+ * Update BD pointer to next entry. 196196+ */197197+ if ((sc & BD_ENET_RX_WRAP) == 0)198198+ bdp++;199199+ else200200+ bdp = fep->rx_bd_base;201201+202202+ (*fep->ops->rx_bd_done)(dev);203203+ }204204+205205+ fep->cur_rx = bdp;206206+207207+ dev->quota -= received;208208+ *budget -= received;209209+210210+ if (rx_work_limit < 0)211211+ return 1; /* not done */212212+213213+ /* done */214214+ netif_rx_complete(dev);215215+216216+ (*fep->ops->napi_enable_rx)(dev);217217+218218+ return 0;219219+}220220+221221+/* non NAPI receive function */222222+static int fs_enet_rx_non_napi(struct net_device *dev)223223+{224224+ struct fs_enet_private *fep = netdev_priv(dev);225225+ const struct fs_platform_info *fpi = fep->fpi;226226+ cbd_t *bdp;227227+ struct sk_buff *skb, *skbn, *skbt;228228+ int received = 0;229229+ u16 pkt_len, sc;230230+ int curidx;231231+ /*232232+ * First, grab all of the stats for the incoming packet.233233+ * These get messed up if we get called due to a busy condition.234234+ */235235+ bdp = fep->cur_rx;236236+237237+ while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {238238+239239+ curidx = bdp - fep->rx_bd_base;240240+241241+ /*242242+ * Since we have allocated space to hold a complete frame,243243+ * the last indicator should be set.244244+ */245245+ if ((sc & BD_ENET_RX_LAST) == 0)246246+ printk(KERN_WARNING DRV_MODULE_NAME247247+ ": %s rcv is not +last\n",248248+ dev->name);249249+250250+ /*251251+ * Check for errors. 252252+ */253253+ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |254254+ BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {255255+ fep->stats.rx_errors++;256256+ /* Frame too long or too short. */257257+ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))258258+ fep->stats.rx_length_errors++;259259+ /* Frame alignment */260260+ if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL))261261+ fep->stats.rx_frame_errors++;262262+ /* CRC Error */263263+ if (sc & BD_ENET_RX_CR)264264+ fep->stats.rx_crc_errors++;265265+ /* FIFO overrun */266266+ if (sc & BD_ENET_RX_OV)267267+ fep->stats.rx_crc_errors++;268268+269269+ skb = fep->rx_skbuff[curidx];270270+271271+ dma_unmap_single(fep->dev, skb->data,272272+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),273273+ DMA_FROM_DEVICE);274274+275275+ skbn = skb;276276+277277+ } else {278278+279279+ skb = fep->rx_skbuff[curidx];280280+281281+ dma_unmap_single(fep->dev, skb->data,282282+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),283283+ DMA_FROM_DEVICE);284284+285285+ /*286286+ * Process the incoming frame.287287+ */288288+ fep->stats.rx_packets++;289289+ pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */290290+ fep->stats.rx_bytes += pkt_len + 4;291291+292292+ if (pkt_len <= fpi->rx_copybreak) {293293+ /* +2 to make IP header L1 cache aligned */294294+ skbn = dev_alloc_skb(pkt_len + 2);295295+ if (skbn != NULL) {296296+ skb_reserve(skbn, 2); /* align IP header */297297+ memcpy(skbn->data, skb->data, pkt_len);298298+ /* swap */299299+ skbt = skb;300300+ skb = skbn;301301+ skbn = skbt;302302+ }303303+ } else304304+ skbn = dev_alloc_skb(ENET_RX_FRSIZE);305305+306306+ if (skbn != NULL) {307307+ skb->dev = dev;308308+ skb_put(skb, pkt_len); /* Make room */309309+ skb->protocol = eth_type_trans(skb, dev);310310+ received++;311311+ netif_rx(skb);312312+ } else {313313+ printk(KERN_WARNING DRV_MODULE_NAME314314+ ": %s Memory squeeze, dropping packet.\n",315315+ dev->name);316316+ fep->stats.rx_dropped++;317317+ skbn = skb;318318+ }319319+ }320320+321321+ fep->rx_skbuff[curidx] = skbn;322322+ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data,323323+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),324324+ DMA_FROM_DEVICE));325325+ CBDW_DATLEN(bdp, 0);326326+ CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);327327+328328+ /*329329+ * Update BD pointer to next entry. 330330+ */331331+ if ((sc & BD_ENET_RX_WRAP) == 0)332332+ bdp++;333333+ else334334+ bdp = fep->rx_bd_base;335335+336336+ (*fep->ops->rx_bd_done)(dev);337337+ }338338+339339+ fep->cur_rx = bdp;340340+341341+ return 0;342342+}343343+344344+static void fs_enet_tx(struct net_device *dev)345345+{346346+ struct fs_enet_private *fep = netdev_priv(dev);347347+ cbd_t *bdp;348348+ struct sk_buff *skb;349349+ int dirtyidx, do_wake, do_restart;350350+ u16 sc;351351+352352+ spin_lock(&fep->lock);353353+ bdp = fep->dirty_tx;354354+355355+ do_wake = do_restart = 0;356356+ while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) {357357+358358+ dirtyidx = bdp - fep->tx_bd_base;359359+360360+ if (fep->tx_free == fep->tx_ring)361361+ break;362362+363363+ skb = fep->tx_skbuff[dirtyidx];364364+365365+ /*366366+ * Check for errors. 367367+ */368368+ if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |369369+ BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) {370370+371371+ if (sc & BD_ENET_TX_HB) /* No heartbeat */372372+ fep->stats.tx_heartbeat_errors++;373373+ if (sc & BD_ENET_TX_LC) /* Late collision */374374+ fep->stats.tx_window_errors++;375375+ if (sc & BD_ENET_TX_RL) /* Retrans limit */376376+ fep->stats.tx_aborted_errors++;377377+ if (sc & BD_ENET_TX_UN) /* Underrun */378378+ fep->stats.tx_fifo_errors++;379379+ if (sc & BD_ENET_TX_CSL) /* Carrier lost */380380+ fep->stats.tx_carrier_errors++;381381+382382+ if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {383383+ fep->stats.tx_errors++;384384+ do_restart = 1;385385+ }386386+ } else387387+ fep->stats.tx_packets++;388388+389389+ if (sc & BD_ENET_TX_READY)390390+ printk(KERN_WARNING DRV_MODULE_NAME391391+ ": %s HEY! Enet xmit interrupt and TX_READY.\n",392392+ dev->name);393393+394394+ /*395395+ * Deferred means some collisions occurred during transmit,396396+ * but we eventually sent the packet OK.397397+ */398398+ if (sc & BD_ENET_TX_DEF)399399+ fep->stats.collisions++;400400+401401+ /* unmap */402402+ dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE);403403+404404+ /*405405+ * Free the sk buffer associated with this last transmit. 406406+ */407407+ dev_kfree_skb_irq(skb);408408+ fep->tx_skbuff[dirtyidx] = NULL;409409+410410+ /*411411+ * Update pointer to next buffer descriptor to be transmitted. 412412+ */413413+ if ((sc & BD_ENET_TX_WRAP) == 0)414414+ bdp++;415415+ else416416+ bdp = fep->tx_bd_base;417417+418418+ /*419419+ * Since we have freed up a buffer, the ring is no longer420420+ * full.421421+ */422422+ if (!fep->tx_free++)423423+ do_wake = 1;424424+ }425425+426426+ fep->dirty_tx = bdp;427427+428428+ if (do_restart)429429+ (*fep->ops->tx_restart)(dev);430430+431431+ spin_unlock(&fep->lock);432432+433433+ if (do_wake)434434+ netif_wake_queue(dev);435435+}436436+437437+/*438438+ * The interrupt handler.439439+ * This is called from the MPC core interrupt.440440+ */441441+static irqreturn_t442442+fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)443443+{444444+ struct net_device *dev = dev_id;445445+ struct fs_enet_private *fep;446446+ const struct fs_platform_info *fpi;447447+ u32 int_events;448448+ u32 int_clr_events;449449+ int nr, napi_ok;450450+ int handled;451451+452452+ fep = netdev_priv(dev);453453+ fpi = fep->fpi;454454+455455+ nr = 0;456456+ while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) {457457+458458+ nr++;459459+460460+ int_clr_events = int_events;461461+ if (fpi->use_napi)462462+ int_clr_events &= ~fep->ev_napi_rx;463463+464464+ (*fep->ops->clear_int_events)(dev, int_clr_events);465465+466466+ if (int_events & fep->ev_err)467467+ (*fep->ops->ev_error)(dev, int_events);468468+469469+ if (int_events & fep->ev_rx) {470470+ if (!fpi->use_napi)471471+ fs_enet_rx_non_napi(dev);472472+ else {473473+ napi_ok = netif_rx_schedule_prep(dev);474474+475475+ (*fep->ops->napi_disable_rx)(dev);476476+ (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx);477477+478478+ /* NOTE: it is possible for FCCs in NAPI mode */479479+ /* to submit a spurious interrupt while in poll */480480+ if (napi_ok)481481+ __netif_rx_schedule(dev);482482+ }483483+ }484484+485485+ if (int_events & fep->ev_tx)486486+ fs_enet_tx(dev);487487+ }488488+489489+ handled = nr > 0;490490+ return IRQ_RETVAL(handled);491491+}492492+493493+void fs_init_bds(struct net_device *dev)494494+{495495+ struct fs_enet_private *fep = netdev_priv(dev);496496+ cbd_t *bdp;497497+ struct sk_buff *skb;498498+ int i;499499+500500+ fs_cleanup_bds(dev);501501+502502+ fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;503503+ fep->tx_free = fep->tx_ring;504504+ fep->cur_rx = fep->rx_bd_base;505505+506506+ /*507507+ * Initialize the receive buffer descriptors. 508508+ */509509+ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {510510+ skb = dev_alloc_skb(ENET_RX_FRSIZE);511511+ if (skb == NULL) {512512+ printk(KERN_WARNING DRV_MODULE_NAME513513+ ": %s Memory squeeze, unable to allocate skb\n",514514+ dev->name);515515+ break;516516+ }517517+ fep->rx_skbuff[i] = skb;518518+ skb->dev = dev;519519+ CBDW_BUFADDR(bdp,520520+ dma_map_single(fep->dev, skb->data,521521+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),522522+ DMA_FROM_DEVICE));523523+ CBDW_DATLEN(bdp, 0); /* zero */524524+ CBDW_SC(bdp, BD_ENET_RX_EMPTY |525525+ ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP));526526+ }527527+ /*528528+ * if we failed, fillup remainder 529529+ */530530+ for (; i < fep->rx_ring; i++, bdp++) {531531+ fep->rx_skbuff[i] = NULL;532532+ CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP);533533+ }534534+535535+ /*536536+ * ...and the same for transmit. 537537+ */538538+ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {539539+ fep->tx_skbuff[i] = NULL;540540+ CBDW_BUFADDR(bdp, 0);541541+ CBDW_DATLEN(bdp, 0);542542+ CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP);543543+ }544544+}545545+546546+void fs_cleanup_bds(struct net_device *dev)547547+{548548+ struct fs_enet_private *fep = netdev_priv(dev);549549+ struct sk_buff *skb;550550+ int i;551551+552552+ /*553553+ * Reset SKB transmit buffers. 554554+ */555555+ for (i = 0; i < fep->tx_ring; i++) {556556+ if ((skb = fep->tx_skbuff[i]) == NULL)557557+ continue;558558+559559+ /* unmap */560560+ dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE);561561+562562+ fep->tx_skbuff[i] = NULL;563563+ dev_kfree_skb(skb);564564+ }565565+566566+ /*567567+ * Reset SKB receive buffers 568568+ */569569+ for (i = 0; i < fep->rx_ring; i++) {570570+ if ((skb = fep->rx_skbuff[i]) == NULL)571571+ continue;572572+573573+ /* unmap */574574+ dma_unmap_single(fep->dev, skb->data,575575+ L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),576576+ DMA_FROM_DEVICE);577577+578578+ fep->rx_skbuff[i] = NULL;579579+580580+ dev_kfree_skb(skb);581581+ }582582+}583583+584584+/**********************************************************************************/585585+586586+static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)587587+{588588+ struct fs_enet_private *fep = netdev_priv(dev);589589+ cbd_t *bdp;590590+ int curidx;591591+ u16 sc;592592+ unsigned long flags;593593+594594+ spin_lock_irqsave(&fep->tx_lock, flags);595595+596596+ /*597597+ * Fill in a Tx ring entry 598598+ */599599+ bdp = fep->cur_tx;600600+601601+ if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) {602602+ netif_stop_queue(dev);603603+ spin_unlock_irqrestore(&fep->tx_lock, flags);604604+605605+ /*606606+ * Ooops. All transmit buffers are full. Bail out.607607+ * This should not happen, since the tx queue should be stopped.608608+ */609609+ printk(KERN_WARNING DRV_MODULE_NAME610610+ ": %s tx queue full!.\n", dev->name);611611+ return NETDEV_TX_BUSY;612612+ }613613+614614+ curidx = bdp - fep->tx_bd_base;615615+ /*616616+ * Clear all of the status flags. 617617+ */618618+ CBDC_SC(bdp, BD_ENET_TX_STATS);619619+620620+ /*621621+ * Save skb pointer. 622622+ */623623+ fep->tx_skbuff[curidx] = skb;624624+625625+ fep->stats.tx_bytes += skb->len;626626+627627+ /*628628+ * Push the data cache so the CPM does not get stale memory data. 629629+ */630630+ CBDW_BUFADDR(bdp, dma_map_single(fep->dev,631631+ skb->data, skb->len, DMA_TO_DEVICE));632632+ CBDW_DATLEN(bdp, skb->len);633633+634634+ dev->trans_start = jiffies;635635+636636+ /*637637+ * If this was the last BD in the ring, start at the beginning again. 638638+ */639639+ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)640640+ fep->cur_tx++;641641+ else642642+ fep->cur_tx = fep->tx_bd_base;643643+644644+ if (!--fep->tx_free)645645+ netif_stop_queue(dev);646646+647647+ /* Trigger transmission start */648648+ sc = BD_ENET_TX_READY | BD_ENET_TX_INTR |649649+ BD_ENET_TX_LAST | BD_ENET_TX_TC;650650+651651+ /* note that while FEC does not have this bit652652+ * it marks it as available for software use653653+ * yay for hw reuse :) */654654+ if (skb->len <= 60)655655+ sc |= BD_ENET_TX_PAD;656656+ CBDS_SC(bdp, sc);657657+658658+ (*fep->ops->tx_kickstart)(dev);659659+660660+ spin_unlock_irqrestore(&fep->tx_lock, flags);661661+662662+ return NETDEV_TX_OK;663663+}664664+665665+static int fs_request_irq(struct net_device *dev, int irq, const char *name,666666+ irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs))667667+{668668+ struct fs_enet_private *fep = netdev_priv(dev);669669+670670+ (*fep->ops->pre_request_irq)(dev, irq);671671+ return request_irq(irq, irqf, SA_SHIRQ, name, dev);672672+}673673+674674+static void fs_free_irq(struct net_device *dev, int irq)675675+{676676+ struct fs_enet_private *fep = netdev_priv(dev);677677+678678+ free_irq(irq, dev);679679+ (*fep->ops->post_free_irq)(dev, irq);680680+}681681+682682+/**********************************************************************************/683683+684684+/* This interrupt occurs when the PHY detects a link change. */685685+static irqreturn_t686686+fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)687687+{688688+ struct net_device *dev = dev_id;689689+ struct fs_enet_private *fep;690690+ const struct fs_platform_info *fpi;691691+692692+ fep = netdev_priv(dev);693693+ fpi = fep->fpi;694694+695695+ /*696696+ * Acknowledge the interrupt if possible. If we have not697697+ * found the PHY yet we can't process or acknowledge the698698+ * interrupt now. Instead we ignore this interrupt for now,699699+ * which we can do since it is edge triggered. It will be700700+ * acknowledged later by fs_enet_open().701701+ */702702+ if (!fep->phy)703703+ return IRQ_NONE;704704+705705+ fs_mii_ack_int(dev);706706+ fs_mii_link_status_change_check(dev, 0);707707+708708+ return IRQ_HANDLED;709709+}710710+711711+static void fs_timeout(struct net_device *dev)712712+{713713+ struct fs_enet_private *fep = netdev_priv(dev);714714+ unsigned long flags;715715+ int wake = 0;716716+717717+ fep->stats.tx_errors++;718718+719719+ spin_lock_irqsave(&fep->lock, flags);720720+721721+ if (dev->flags & IFF_UP) {722722+ (*fep->ops->stop)(dev);723723+ (*fep->ops->restart)(dev);724724+ }725725+726726+ wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY);727727+ spin_unlock_irqrestore(&fep->lock, flags);728728+729729+ if (wake)730730+ netif_wake_queue(dev);731731+}732732+733733+static int fs_enet_open(struct net_device *dev)734734+{735735+ struct fs_enet_private *fep = netdev_priv(dev);736736+ const struct fs_platform_info *fpi = fep->fpi;737737+ int r;738738+739739+ /* Install our interrupt handler. */740740+ r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);741741+ if (r != 0) {742742+ printk(KERN_ERR DRV_MODULE_NAME743743+ ": %s Could not allocate FEC IRQ!", dev->name);744744+ return -EINVAL;745745+ }746746+747747+ /* Install our phy interrupt handler */748748+ if (fpi->phy_irq != -1) {749749+750750+ r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt);751751+ if (r != 0) {752752+ printk(KERN_ERR DRV_MODULE_NAME753753+ ": %s Could not allocate PHY IRQ!", dev->name);754754+ fs_free_irq(dev, fep->interrupt);755755+ return -EINVAL;756756+ }757757+ }758758+759759+ fs_mii_startup(dev);760760+ netif_carrier_off(dev);761761+ fs_mii_link_status_change_check(dev, 1);762762+763763+ return 0;764764+}765765+766766+static int fs_enet_close(struct net_device *dev)767767+{768768+ struct fs_enet_private *fep = netdev_priv(dev);769769+ const struct fs_platform_info *fpi = fep->fpi;770770+ unsigned long flags;771771+772772+ netif_stop_queue(dev);773773+ netif_carrier_off(dev);774774+ fs_mii_shutdown(dev);775775+776776+ spin_lock_irqsave(&fep->lock, flags);777777+ (*fep->ops->stop)(dev);778778+ spin_unlock_irqrestore(&fep->lock, flags);779779+780780+ /* release any irqs */781781+ if (fpi->phy_irq != -1)782782+ fs_free_irq(dev, fpi->phy_irq);783783+ fs_free_irq(dev, fep->interrupt);784784+785785+ return 0;786786+}787787+788788+static struct net_device_stats *fs_enet_get_stats(struct net_device *dev)789789+{790790+ struct fs_enet_private *fep = netdev_priv(dev);791791+ return &fep->stats;792792+}793793+794794+/*************************************************************************/795795+796796+static void fs_get_drvinfo(struct net_device *dev,797797+ struct ethtool_drvinfo *info)798798+{799799+ strcpy(info->driver, DRV_MODULE_NAME);800800+ strcpy(info->version, DRV_MODULE_VERSION);801801+}802802+803803+static int fs_get_regs_len(struct net_device *dev)804804+{805805+ struct fs_enet_private *fep = netdev_priv(dev);806806+807807+ return (*fep->ops->get_regs_len)(dev);808808+}809809+810810+static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs,811811+ void *p)812812+{813813+ struct fs_enet_private *fep = netdev_priv(dev);814814+ unsigned long flags;815815+ int r, len;816816+817817+ len = regs->len;818818+819819+ spin_lock_irqsave(&fep->lock, flags);820820+ r = (*fep->ops->get_regs)(dev, p, &len);821821+ spin_unlock_irqrestore(&fep->lock, flags);822822+823823+ if (r == 0)824824+ regs->version = 0;825825+}826826+827827+static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)828828+{829829+ struct fs_enet_private *fep = netdev_priv(dev);830830+ unsigned long flags;831831+ int rc;832832+833833+ spin_lock_irqsave(&fep->lock, flags);834834+ rc = mii_ethtool_gset(&fep->mii_if, cmd);835835+ spin_unlock_irqrestore(&fep->lock, flags);836836+837837+ return rc;838838+}839839+840840+static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)841841+{842842+ struct fs_enet_private *fep = netdev_priv(dev);843843+ unsigned long flags;844844+ int rc;845845+846846+ spin_lock_irqsave(&fep->lock, flags);847847+ rc = mii_ethtool_sset(&fep->mii_if, cmd);848848+ spin_unlock_irqrestore(&fep->lock, flags);849849+850850+ return rc;851851+}852852+853853+static int fs_nway_reset(struct net_device *dev)854854+{855855+ struct fs_enet_private *fep = netdev_priv(dev);856856+ return mii_nway_restart(&fep->mii_if);857857+}858858+859859+static u32 fs_get_msglevel(struct net_device *dev)860860+{861861+ struct fs_enet_private *fep = netdev_priv(dev);862862+ return fep->msg_enable;863863+}864864+865865+static void fs_set_msglevel(struct net_device *dev, u32 value)866866+{867867+ struct fs_enet_private *fep = netdev_priv(dev);868868+ fep->msg_enable = value;869869+}870870+871871+static struct ethtool_ops fs_ethtool_ops = {872872+ .get_drvinfo = fs_get_drvinfo,873873+ .get_regs_len = fs_get_regs_len,874874+ .get_settings = fs_get_settings,875875+ .set_settings = fs_set_settings,876876+ .nway_reset = fs_nway_reset,877877+ .get_link = ethtool_op_get_link,878878+ .get_msglevel = fs_get_msglevel,879879+ .set_msglevel = fs_set_msglevel,880880+ .get_tx_csum = ethtool_op_get_tx_csum,881881+ .set_tx_csum = ethtool_op_set_tx_csum, /* local! */882882+ .get_sg = ethtool_op_get_sg,883883+ .set_sg = ethtool_op_set_sg,884884+ .get_regs = fs_get_regs,885885+};886886+887887+static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)888888+{889889+ struct fs_enet_private *fep = netdev_priv(dev);890890+ struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;891891+ unsigned long flags;892892+ int rc;893893+894894+ if (!netif_running(dev))895895+ return -EINVAL;896896+897897+ spin_lock_irqsave(&fep->lock, flags);898898+ rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL);899899+ spin_unlock_irqrestore(&fep->lock, flags);900900+ return rc;901901+}902902+903903+extern int fs_mii_connect(struct net_device *dev);904904+extern void fs_mii_disconnect(struct net_device *dev);905905+906906+static struct net_device *fs_init_instance(struct device *dev,907907+ const struct fs_platform_info *fpi)908908+{909909+ struct net_device *ndev = NULL;910910+ struct fs_enet_private *fep = NULL;911911+ int privsize, i, r, err = 0, registered = 0;912912+913913+ /* guard */914914+ if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX)915915+ return ERR_PTR(-EINVAL);916916+917917+ privsize = sizeof(*fep) + (sizeof(struct sk_buff **) *918918+ (fpi->rx_ring + fpi->tx_ring));919919+920920+ ndev = alloc_etherdev(privsize);921921+ if (!ndev) {922922+ err = -ENOMEM;923923+ goto err;924924+ }925925+ SET_MODULE_OWNER(ndev);926926+927927+ fep = netdev_priv(ndev);928928+ memset(fep, 0, privsize); /* clear everything */929929+930930+ fep->dev = dev;931931+ dev_set_drvdata(dev, ndev);932932+ fep->fpi = fpi;933933+ if (fpi->init_ioports)934934+ fpi->init_ioports();935935+936936+#ifdef CONFIG_FS_ENET_HAS_FEC937937+ if (fs_get_fec_index(fpi->fs_no) >= 0)938938+ fep->ops = &fs_fec_ops;939939+#endif940940+941941+#ifdef CONFIG_FS_ENET_HAS_SCC942942+ if (fs_get_scc_index(fpi->fs_no) >=0 )943943+ fep->ops = &fs_scc_ops;944944+#endif945945+946946+#ifdef CONFIG_FS_ENET_HAS_FCC947947+ if (fs_get_fcc_index(fpi->fs_no) >= 0)948948+ fep->ops = &fs_fcc_ops;949949+#endif950950+951951+ if (fep->ops == NULL) {952952+ printk(KERN_ERR DRV_MODULE_NAME953953+ ": %s No matching ops found (%d).\n",954954+ ndev->name, fpi->fs_no);955955+ err = -EINVAL;956956+ goto err;957957+ }958958+959959+ r = (*fep->ops->setup_data)(ndev);960960+ if (r != 0) {961961+ printk(KERN_ERR DRV_MODULE_NAME962962+ ": %s setup_data failed\n",963963+ ndev->name);964964+ err = r;965965+ goto err;966966+ }967967+968968+ /* point rx_skbuff, tx_skbuff */969969+ fep->rx_skbuff = (struct sk_buff **)&fep[1];970970+ fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;971971+972972+ /* init locks */973973+ spin_lock_init(&fep->lock);974974+ spin_lock_init(&fep->tx_lock);975975+976976+ /*977977+ * Set the Ethernet address. 978978+ */979979+ for (i = 0; i < 6; i++)980980+ ndev->dev_addr[i] = fpi->macaddr[i];981981+982982+ r = (*fep->ops->allocate_bd)(ndev);983983+984984+ if (fep->ring_base == NULL) {985985+ printk(KERN_ERR DRV_MODULE_NAME986986+ ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r);987987+ err = r;988988+ goto err;989989+ }990990+991991+ /*992992+ * Set receive and transmit descriptor base.993993+ */994994+ fep->rx_bd_base = fep->ring_base;995995+ fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;996996+997997+ /* initialize ring size variables */998998+ fep->tx_ring = fpi->tx_ring;999999+ fep->rx_ring = fpi->rx_ring;10001000+10011001+ /*10021002+ * The FEC Ethernet specific entries in the device structure. 10031003+ */10041004+ ndev->open = fs_enet_open;10051005+ ndev->hard_start_xmit = fs_enet_start_xmit;10061006+ ndev->tx_timeout = fs_timeout;10071007+ ndev->watchdog_timeo = 2 * HZ;10081008+ ndev->stop = fs_enet_close;10091009+ ndev->get_stats = fs_enet_get_stats;10101010+ ndev->set_multicast_list = fs_set_multicast_list;10111011+ if (fpi->use_napi) {10121012+ ndev->poll = fs_enet_rx_napi;10131013+ ndev->weight = fpi->napi_weight;10141014+ }10151015+ ndev->ethtool_ops = &fs_ethtool_ops;10161016+ ndev->do_ioctl = fs_ioctl;10171017+10181018+ init_timer(&fep->phy_timer_list);10191019+10201020+ netif_carrier_off(ndev);10211021+10221022+ err = register_netdev(ndev);10231023+ if (err != 0) {10241024+ printk(KERN_ERR DRV_MODULE_NAME10251025+ ": %s register_netdev failed.\n", ndev->name);10261026+ goto err;10271027+ }10281028+ registered = 1;10291029+10301030+ err = fs_mii_connect(ndev);10311031+ if (err != 0) {10321032+ printk(KERN_ERR DRV_MODULE_NAME10331033+ ": %s fs_mii_connect failed.\n", ndev->name);10341034+ goto err;10351035+ }10361036+10371037+ return ndev;10381038+10391039+ err:10401040+ if (ndev != NULL) {10411041+10421042+ if (registered)10431043+ unregister_netdev(ndev);10441044+10451045+ if (fep != NULL) {10461046+ (*fep->ops->free_bd)(ndev);10471047+ (*fep->ops->cleanup_data)(ndev);10481048+ }10491049+10501050+ free_netdev(ndev);10511051+ }10521052+10531053+ dev_set_drvdata(dev, NULL);10541054+10551055+ return ERR_PTR(err);10561056+}10571057+10581058+static int fs_cleanup_instance(struct net_device *ndev)10591059+{10601060+ struct fs_enet_private *fep;10611061+ const struct fs_platform_info *fpi;10621062+ struct device *dev;10631063+10641064+ if (ndev == NULL)10651065+ return -EINVAL;10661066+10671067+ fep = netdev_priv(ndev);10681068+ if (fep == NULL)10691069+ return -EINVAL;10701070+10711071+ fpi = fep->fpi;10721072+10731073+ fs_mii_disconnect(ndev);10741074+10751075+ unregister_netdev(ndev);10761076+10771077+ dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),10781078+ fep->ring_base, fep->ring_mem_addr);10791079+10801080+ /* reset it */10811081+ (*fep->ops->cleanup_data)(ndev);10821082+10831083+ dev = fep->dev;10841084+ if (dev != NULL) {10851085+ dev_set_drvdata(dev, NULL);10861086+ fep->dev = NULL;10871087+ }10881088+10891089+ free_netdev(ndev);10901090+10911091+ return 0;10921092+}10931093+10941094+/**************************************************************************************/10951095+10961096+/* handy pointer to the immap */10971097+void *fs_enet_immap = NULL;10981098+10991099+static int setup_immap(void)11001100+{11011101+ phys_addr_t paddr = 0;11021102+ unsigned long size = 0;11031103+11041104+#ifdef CONFIG_CPM111051105+ paddr = IMAP_ADDR;11061106+ size = 0x10000; /* map 64K */11071107+#endif11081108+11091109+#ifdef CONFIG_CPM211101110+ paddr = CPM_MAP_ADDR;11111111+ size = 0x40000; /* map 256 K */11121112+#endif11131113+ fs_enet_immap = ioremap(paddr, size);11141114+ if (fs_enet_immap == NULL)11151115+ return -EBADF; /* XXX ahem; maybe just BUG_ON? */11161116+11171117+ return 0;11181118+}11191119+11201120+static void cleanup_immap(void)11211121+{11221122+ if (fs_enet_immap != NULL) {11231123+ iounmap(fs_enet_immap);11241124+ fs_enet_immap = NULL;11251125+ }11261126+}11271127+11281128+/**************************************************************************************/11291129+11301130+static int __devinit fs_enet_probe(struct device *dev)11311131+{11321132+ struct net_device *ndev;11331133+11341134+ /* no fixup - no device */11351135+ if (dev->platform_data == NULL) {11361136+ printk(KERN_INFO "fs_enet: "11371137+ "probe called with no platform data; "11381138+ "remove unused devices\n");11391139+ return -ENODEV;11401140+ }11411141+11421142+ ndev = fs_init_instance(dev, dev->platform_data);11431143+ if (IS_ERR(ndev))11441144+ return PTR_ERR(ndev);11451145+ return 0;11461146+}11471147+11481148+static int fs_enet_remove(struct device *dev)11491149+{11501150+ return fs_cleanup_instance(dev_get_drvdata(dev));11511151+}11521152+11531153+static struct device_driver fs_enet_fec_driver = {11541154+ .name = "fsl-cpm-fec",11551155+ .bus = &platform_bus_type,11561156+ .probe = fs_enet_probe,11571157+ .remove = fs_enet_remove,11581158+#ifdef CONFIG_PM11591159+/* .suspend = fs_enet_suspend, TODO */11601160+/* .resume = fs_enet_resume, TODO */11611161+#endif11621162+};11631163+11641164+static struct device_driver fs_enet_scc_driver = {11651165+ .name = "fsl-cpm-scc",11661166+ .bus = &platform_bus_type,11671167+ .probe = fs_enet_probe,11681168+ .remove = fs_enet_remove,11691169+#ifdef CONFIG_PM11701170+/* .suspend = fs_enet_suspend, TODO */11711171+/* .resume = fs_enet_resume, TODO */11721172+#endif11731173+};11741174+11751175+static struct device_driver fs_enet_fcc_driver = {11761176+ .name = "fsl-cpm-fcc",11771177+ .bus = &platform_bus_type,11781178+ .probe = fs_enet_probe,11791179+ .remove = fs_enet_remove,11801180+#ifdef CONFIG_PM11811181+/* .suspend = fs_enet_suspend, TODO */11821182+/* .resume = fs_enet_resume, TODO */11831183+#endif11841184+};11851185+11861186+static int __init fs_init(void)11871187+{11881188+ int r;11891189+11901190+ printk(KERN_INFO11911191+ "%s", version);11921192+11931193+ r = setup_immap();11941194+ if (r != 0)11951195+ return r;11961196+ r = driver_register(&fs_enet_fec_driver);11971197+ if (r != 0)11981198+ goto err;11991199+12001200+ r = driver_register(&fs_enet_fcc_driver);12011201+ if (r != 0)12021202+ goto err;12031203+12041204+ r = driver_register(&fs_enet_scc_driver);12051205+ if (r != 0)12061206+ goto err;12071207+12081208+ return 0;12091209+err:12101210+ cleanup_immap();12111211+ return r;12121212+12131213+}12141214+12151215+static void __exit fs_cleanup(void)12161216+{12171217+ driver_unregister(&fs_enet_fec_driver);12181218+ driver_unregister(&fs_enet_fcc_driver);12191219+ driver_unregister(&fs_enet_scc_driver);12201220+ cleanup_immap();12211221+}12221222+12231223+/**************************************************************************************/12241224+12251225+module_init(fs_init);12261226+module_exit(fs_cleanup);
+507
drivers/net/fs_enet/fs_enet-mii.c
···11+/*22+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.33+ *44+ * Copyright (c) 2003 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ * 77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>1111+ * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>1212+ *1313+ * This file is licensed under the terms of the GNU General Public License 1414+ * version 2. This program is licensed "as is" without any warranty of any 1515+ * kind, whether express or implied.1616+ */1717+1818+1919+#include <linux/config.h>2020+#include <linux/module.h>2121+#include <linux/types.h>2222+#include <linux/kernel.h>2323+#include <linux/sched.h>2424+#include <linux/string.h>2525+#include <linux/ptrace.h>2626+#include <linux/errno.h>2727+#include <linux/ioport.h>2828+#include <linux/slab.h>2929+#include <linux/interrupt.h>3030+#include <linux/pci.h>3131+#include <linux/init.h>3232+#include <linux/delay.h>3333+#include <linux/netdevice.h>3434+#include <linux/etherdevice.h>3535+#include <linux/skbuff.h>3636+#include <linux/spinlock.h>3737+#include <linux/mii.h>3838+#include <linux/ethtool.h>3939+#include <linux/bitops.h>4040+4141+#include <asm/pgtable.h>4242+#include <asm/irq.h>4343+#include <asm/uaccess.h>4444+4545+#include "fs_enet.h"4646+4747+/*************************************************/4848+4949+/*5050+ * Generic PHY support.5151+ * Should work for all PHYs, but link change is detected by polling5252+ */5353+5454+static void generic_timer_callback(unsigned long data)5555+{5656+ struct net_device *dev = (struct net_device *)data;5757+ struct fs_enet_private *fep = netdev_priv(dev);5858+5959+ fep->phy_timer_list.expires = jiffies + HZ / 2;6060+6161+ add_timer(&fep->phy_timer_list);6262+6363+ fs_mii_link_status_change_check(dev, 0);6464+}6565+6666+static void generic_startup(struct net_device *dev)6767+{6868+ struct fs_enet_private *fep = netdev_priv(dev);6969+7070+ fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */7171+ fep->phy_timer_list.data = (unsigned long)dev;7272+ fep->phy_timer_list.function = generic_timer_callback;7373+ add_timer(&fep->phy_timer_list);7474+}7575+7676+static void generic_shutdown(struct net_device *dev)7777+{7878+ struct fs_enet_private *fep = netdev_priv(dev);7979+8080+ del_timer_sync(&fep->phy_timer_list);8181+}8282+8383+/* ------------------------------------------------------------------------- */8484+/* The Davicom DM9161 is used on the NETTA board */8585+8686+/* register definitions */8787+8888+#define MII_DM9161_ANAR 4 /* Aux. Config Register */8989+#define MII_DM9161_ACR 16 /* Aux. Config Register */9090+#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */9191+#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */9292+#define MII_DM9161_INTR 21 /* Interrupt Register */9393+#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */9494+#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */9595+9696+static void dm9161_startup(struct net_device *dev)9797+{9898+ struct fs_enet_private *fep = netdev_priv(dev);9999+100100+ fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);101101+ /* Start autonegotiation */102102+ fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200);103103+104104+ set_current_state(TASK_UNINTERRUPTIBLE);105105+ schedule_timeout(HZ*8);106106+}107107+108108+static void dm9161_ack_int(struct net_device *dev)109109+{110110+ struct fs_enet_private *fep = netdev_priv(dev);111111+112112+ fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);113113+}114114+115115+static void dm9161_shutdown(struct net_device *dev)116116+{117117+ struct fs_enet_private *fep = netdev_priv(dev);118118+119119+ fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);120120+}121121+122122+/**********************************************************************************/123123+124124+static const struct phy_info phy_info[] = {125125+ {126126+ .id = 0x00181b88,127127+ .name = "DM9161",128128+ .startup = dm9161_startup,129129+ .ack_int = dm9161_ack_int,130130+ .shutdown = dm9161_shutdown,131131+ }, {132132+ .id = 0,133133+ .name = "GENERIC",134134+ .startup = generic_startup,135135+ .shutdown = generic_shutdown,136136+ },137137+};138138+139139+/**********************************************************************************/140140+141141+static int phy_id_detect(struct net_device *dev)142142+{143143+ struct fs_enet_private *fep = netdev_priv(dev);144144+ const struct fs_platform_info *fpi = fep->fpi;145145+ struct fs_enet_mii_bus *bus = fep->mii_bus;146146+ int i, r, start, end, phytype, physubtype;147147+ const struct phy_info *phy;148148+ int phy_hwid, phy_id;149149+150150+ phy_hwid = -1;151151+ fep->phy = NULL;152152+153153+ /* auto-detect? */154154+ if (fpi->phy_addr == -1) {155155+ start = 1;156156+ end = 32;157157+ } else { /* direct */158158+ start = fpi->phy_addr;159159+ end = start + 1;160160+ }161161+162162+ for (phy_id = start; phy_id < end; phy_id++) {163163+ /* skip already used phy addresses on this bus */ 164164+ if (bus->usage_map & (1 << phy_id))165165+ continue;166166+ r = fs_mii_read(dev, phy_id, MII_PHYSID1);167167+ if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)168168+ continue;169169+ r = fs_mii_read(dev, phy_id, MII_PHYSID2);170170+ if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)171171+ continue;172172+ phy_hwid = (phytype << 16) | physubtype;173173+ if (phy_hwid != -1)174174+ break;175175+ }176176+177177+ if (phy_hwid == -1) {178178+ printk(KERN_ERR DRV_MODULE_NAME179179+ ": %s No PHY detected! range=0x%02x-0x%02x\n",180180+ dev->name, start, end);181181+ return -1;182182+ }183183+184184+ for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)185185+ if (phy->id == (phy_hwid >> 4) || phy->id == 0)186186+ break;187187+188188+ if (i >= ARRAY_SIZE(phy_info)) {189189+ printk(KERN_ERR DRV_MODULE_NAME190190+ ": %s PHY id 0x%08x is not supported!\n",191191+ dev->name, phy_hwid);192192+ return -1;193193+ }194194+195195+ fep->phy = phy;196196+197197+ /* mark this address as used */198198+ bus->usage_map |= (1 << phy_id);199199+200200+ printk(KERN_INFO DRV_MODULE_NAME201201+ ": %s Phy @ 0x%x, type %s (0x%08x)%s\n",202202+ dev->name, phy_id, fep->phy->name, phy_hwid,203203+ fpi->phy_addr == -1 ? " (auto-detected)" : "");204204+205205+ return phy_id;206206+}207207+208208+void fs_mii_startup(struct net_device *dev)209209+{210210+ struct fs_enet_private *fep = netdev_priv(dev);211211+212212+ if (fep->phy->startup)213213+ (*fep->phy->startup) (dev);214214+}215215+216216+void fs_mii_shutdown(struct net_device *dev)217217+{218218+ struct fs_enet_private *fep = netdev_priv(dev);219219+220220+ if (fep->phy->shutdown)221221+ (*fep->phy->shutdown) (dev);222222+}223223+224224+void fs_mii_ack_int(struct net_device *dev)225225+{226226+ struct fs_enet_private *fep = netdev_priv(dev);227227+228228+ if (fep->phy->ack_int)229229+ (*fep->phy->ack_int) (dev);230230+}231231+232232+#define MII_LINK 0x0001233233+#define MII_HALF 0x0002234234+#define MII_FULL 0x0004235235+#define MII_BASE4 0x0008236236+#define MII_10M 0x0010237237+#define MII_100M 0x0020238238+#define MII_1G 0x0040239239+#define MII_10G 0x0080240240+241241+/* return full mii info at one gulp, with a usable form */242242+static unsigned int mii_full_status(struct mii_if_info *mii)243243+{244244+ unsigned int status;245245+ int bmsr, adv, lpa, neg;246246+ struct fs_enet_private* fep = netdev_priv(mii->dev);247247+248248+ /* first, a dummy read, needed to latch some MII phys */249249+ (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);250250+ bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);251251+252252+ /* no link */253253+ if ((bmsr & BMSR_LSTATUS) == 0)254254+ return 0;255255+256256+ status = MII_LINK;257257+258258+ /* Lets look what ANEG says if it's supported - otherwize we shall259259+ take the right values from the platform info*/260260+ if(!mii->force_media) {261261+ /* autoneg not completed; don't bother */262262+ if ((bmsr & BMSR_ANEGCOMPLETE) == 0)263263+ return 0;264264+265265+ adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE);266266+ lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA);267267+268268+ neg = lpa & adv;269269+ } else {270270+ neg = fep->fpi->bus_info->lpa;271271+ }272272+273273+ if (neg & LPA_100FULL)274274+ status |= MII_FULL | MII_100M;275275+ else if (neg & LPA_100BASE4)276276+ status |= MII_FULL | MII_BASE4 | MII_100M;277277+ else if (neg & LPA_100HALF)278278+ status |= MII_HALF | MII_100M;279279+ else if (neg & LPA_10FULL)280280+ status |= MII_FULL | MII_10M;281281+ else282282+ status |= MII_HALF | MII_10M;283283+284284+ return status;285285+}286286+287287+void fs_mii_link_status_change_check(struct net_device *dev, int init_media)288288+{289289+ struct fs_enet_private *fep = netdev_priv(dev);290290+ struct mii_if_info *mii = &fep->mii_if;291291+ unsigned int mii_status;292292+ int ok_to_print, link, duplex, speed;293293+ unsigned long flags;294294+295295+ ok_to_print = netif_msg_link(fep);296296+297297+ mii_status = mii_full_status(mii);298298+299299+ if (!init_media && mii_status == fep->last_mii_status)300300+ return;301301+302302+ fep->last_mii_status = mii_status;303303+304304+ link = !!(mii_status & MII_LINK);305305+ duplex = !!(mii_status & MII_FULL);306306+ speed = (mii_status & MII_100M) ? 100 : 10;307307+308308+ if (link == 0) {309309+ netif_carrier_off(mii->dev);310310+ netif_stop_queue(dev);311311+ if (!init_media) {312312+ spin_lock_irqsave(&fep->lock, flags);313313+ (*fep->ops->stop)(dev);314314+ spin_unlock_irqrestore(&fep->lock, flags);315315+ }316316+317317+ if (ok_to_print)318318+ printk(KERN_INFO "%s: link down\n", mii->dev->name);319319+320320+ } else {321321+322322+ mii->full_duplex = duplex;323323+324324+ netif_carrier_on(mii->dev);325325+326326+ spin_lock_irqsave(&fep->lock, flags);327327+ fep->duplex = duplex;328328+ fep->speed = speed;329329+ (*fep->ops->restart)(dev);330330+ spin_unlock_irqrestore(&fep->lock, flags);331331+332332+ netif_start_queue(dev);333333+334334+ if (ok_to_print)335335+ printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n",336336+ dev->name, speed, duplex ? "full" : "half");337337+ }338338+}339339+340340+/**********************************************************************************/341341+342342+int fs_mii_read(struct net_device *dev, int phy_id, int location)343343+{344344+ struct fs_enet_private *fep = netdev_priv(dev);345345+ struct fs_enet_mii_bus *bus = fep->mii_bus;346346+347347+ unsigned long flags;348348+ int ret;349349+350350+ spin_lock_irqsave(&bus->mii_lock, flags);351351+ ret = (*bus->mii_read)(bus, phy_id, location);352352+ spin_unlock_irqrestore(&bus->mii_lock, flags);353353+354354+ return ret;355355+}356356+357357+void fs_mii_write(struct net_device *dev, int phy_id, int location, int value)358358+{359359+ struct fs_enet_private *fep = netdev_priv(dev);360360+ struct fs_enet_mii_bus *bus = fep->mii_bus;361361+ unsigned long flags;362362+363363+ spin_lock_irqsave(&bus->mii_lock, flags);364364+ (*bus->mii_write)(bus, phy_id, location, value);365365+ spin_unlock_irqrestore(&bus->mii_lock, flags);366366+}367367+368368+/*****************************************************************************/369369+370370+/* list of all registered mii buses */371371+static LIST_HEAD(fs_mii_bus_list);372372+373373+static struct fs_enet_mii_bus *lookup_bus(int method, int id)374374+{375375+ struct list_head *ptr;376376+ struct fs_enet_mii_bus *bus;377377+378378+ list_for_each(ptr, &fs_mii_bus_list) {379379+ bus = list_entry(ptr, struct fs_enet_mii_bus, list);380380+ if (bus->bus_info->method == method &&381381+ bus->bus_info->id == id)382382+ return bus;383383+ }384384+ return NULL;385385+}386386+387387+static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)388388+{389389+ struct fs_enet_mii_bus *bus;390390+ int ret = 0;391391+392392+ bus = kmalloc(sizeof(*bus), GFP_KERNEL);393393+ if (bus == NULL) {394394+ ret = -ENOMEM;395395+ goto err;396396+ }397397+ memset(bus, 0, sizeof(*bus));398398+ spin_lock_init(&bus->mii_lock);399399+ bus->bus_info = bi;400400+ bus->refs = 0;401401+ bus->usage_map = 0;402402+403403+ /* perform initialization */404404+ switch (bi->method) {405405+406406+ case fsmii_fixed:407407+ ret = fs_mii_fixed_init(bus);408408+ if (ret != 0)409409+ goto err;410410+ break;411411+412412+ case fsmii_bitbang:413413+ ret = fs_mii_bitbang_init(bus);414414+ if (ret != 0)415415+ goto err;416416+ break;417417+#ifdef CONFIG_FS_ENET_HAS_FEC418418+ case fsmii_fec:419419+ ret = fs_mii_fec_init(bus);420420+ if (ret != 0)421421+ goto err;422422+ break;423423+#endif424424+ default:425425+ ret = -EINVAL;426426+ goto err;427427+ }428428+429429+ list_add(&bus->list, &fs_mii_bus_list);430430+431431+ return bus;432432+433433+err:434434+ if (bus)435435+ kfree(bus);436436+ return ERR_PTR(ret);437437+}438438+439439+static void destroy_bus(struct fs_enet_mii_bus *bus)440440+{441441+ /* remove from bus list */442442+ list_del(&bus->list);443443+444444+ /* nothing more needed */445445+ kfree(bus);446446+}447447+448448+int fs_mii_connect(struct net_device *dev)449449+{450450+ struct fs_enet_private *fep = netdev_priv(dev);451451+ const struct fs_platform_info *fpi = fep->fpi;452452+ struct fs_enet_mii_bus *bus = NULL;453453+454454+ /* check method validity */455455+ switch (fpi->bus_info->method) {456456+ case fsmii_fixed:457457+ case fsmii_bitbang:458458+ break;459459+#ifdef CONFIG_FS_ENET_HAS_FEC460460+ case fsmii_fec:461461+ break;462462+#endif463463+ default:464464+ printk(KERN_ERR DRV_MODULE_NAME465465+ ": %s Unknown MII bus method (%d)!\n",466466+ dev->name, fpi->bus_info->method);467467+ return -EINVAL; 468468+ }469469+470470+ bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id);471471+472472+ /* if not found create new bus */473473+ if (bus == NULL) {474474+ bus = create_bus(fpi->bus_info);475475+ if (IS_ERR(bus)) {476476+ printk(KERN_ERR DRV_MODULE_NAME477477+ ": %s MII bus creation failure!\n", dev->name);478478+ return PTR_ERR(bus);479479+ }480480+ }481481+482482+ bus->refs++;483483+484484+ fep->mii_bus = bus;485485+486486+ fep->mii_if.dev = dev;487487+ fep->mii_if.phy_id_mask = 0x1f;488488+ fep->mii_if.reg_num_mask = 0x1f;489489+ fep->mii_if.mdio_read = fs_mii_read;490490+ fep->mii_if.mdio_write = fs_mii_write;491491+ fep->mii_if.force_media = fpi->bus_info->disable_aneg;492492+ fep->mii_if.phy_id = phy_id_detect(dev);493493+494494+ return 0;495495+}496496+497497+void fs_mii_disconnect(struct net_device *dev)498498+{499499+ struct fs_enet_private *fep = netdev_priv(dev);500500+ struct fs_enet_mii_bus *bus = NULL;501501+502502+ bus = fep->mii_bus;503503+ fep->mii_bus = NULL;504504+505505+ if (--bus->refs <= 0)506506+ destroy_bus(bus);507507+}
+245
drivers/net/fs_enet/fs_enet.h
···11+#ifndef FS_ENET_H22+#define FS_ENET_H33+44+#include <linux/mii.h>55+#include <linux/netdevice.h>66+#include <linux/types.h>77+#include <linux/version.h>88+#include <linux/list.h>99+1010+#include <linux/fs_enet_pd.h>1111+1212+#include <asm/dma-mapping.h>1313+1414+#ifdef CONFIG_CPM11515+#include <asm/commproc.h>1616+#endif1717+1818+#ifdef CONFIG_CPM21919+#include <asm/cpm2.h>2020+#endif2121+2222+/* hw driver ops */2323+struct fs_ops {2424+ int (*setup_data)(struct net_device *dev);2525+ int (*allocate_bd)(struct net_device *dev);2626+ void (*free_bd)(struct net_device *dev);2727+ void (*cleanup_data)(struct net_device *dev);2828+ void (*set_multicast_list)(struct net_device *dev);2929+ void (*restart)(struct net_device *dev);3030+ void (*stop)(struct net_device *dev);3131+ void (*pre_request_irq)(struct net_device *dev, int irq);3232+ void (*post_free_irq)(struct net_device *dev, int irq);3333+ void (*napi_clear_rx_event)(struct net_device *dev);3434+ void (*napi_enable_rx)(struct net_device *dev);3535+ void (*napi_disable_rx)(struct net_device *dev);3636+ void (*rx_bd_done)(struct net_device *dev);3737+ void (*tx_kickstart)(struct net_device *dev);3838+ u32 (*get_int_events)(struct net_device *dev);3939+ void (*clear_int_events)(struct net_device *dev, u32 int_events);4040+ void (*ev_error)(struct net_device *dev, u32 int_events);4141+ int (*get_regs)(struct net_device *dev, void *p, int *sizep);4242+ int (*get_regs_len)(struct net_device *dev);4343+ void (*tx_restart)(struct net_device *dev);4444+};4545+4646+struct phy_info {4747+ unsigned int id;4848+ const char *name;4949+ void (*startup) (struct net_device * dev);5050+ void (*shutdown) (struct net_device * dev);5151+ void (*ack_int) (struct net_device * dev);5252+};5353+5454+/* The FEC stores dest/src/type, data, and checksum for receive packets.5555+ */5656+#define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */5757+#define MIN_MTU 46 /* this is data size */5858+#define CRC_LEN 45959+6060+#define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN)6161+#define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN)6262+6363+/* Must be a multiple of 32 (to cover both FEC & FCC) */6464+#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31)6565+/* This is needed so that invalidate_xxx wont invalidate too much */6666+#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE)6767+6868+struct fs_enet_mii_bus {6969+ struct list_head list;7070+ spinlock_t mii_lock;7171+ const struct fs_mii_bus_info *bus_info;7272+ int refs;7373+ u32 usage_map;7474+7575+ int (*mii_read)(struct fs_enet_mii_bus *bus,7676+ int phy_id, int location);7777+7878+ void (*mii_write)(struct fs_enet_mii_bus *bus,7979+ int phy_id, int location, int value);8080+8181+ union {8282+ struct {8383+ unsigned int mii_speed;8484+ void *fecp;8585+ } fec;8686+8787+ struct {8888+ /* note that the actual port size may */8989+ /* be different; cpm(s) handle it OK */9090+ u8 mdio_msk;9191+ u8 *mdio_dir;9292+ u8 *mdio_dat;9393+ u8 mdc_msk;9494+ u8 *mdc_dir;9595+ u8 *mdc_dat;9696+ } bitbang;9797+9898+ struct {9999+ u16 lpa;100100+ } fixed;101101+ };102102+};103103+104104+int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus);105105+int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);106106+int fs_mii_fec_init(struct fs_enet_mii_bus *bus);107107+108108+struct fs_enet_private {109109+ struct device *dev; /* pointer back to the device (must be initialized first) */110110+ spinlock_t lock; /* during all ops except TX pckt processing */111111+ spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */112112+ const struct fs_platform_info *fpi;113113+ const struct fs_ops *ops;114114+ int rx_ring, tx_ring;115115+ dma_addr_t ring_mem_addr;116116+ void *ring_base;117117+ struct sk_buff **rx_skbuff;118118+ struct sk_buff **tx_skbuff;119119+ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */120120+ cbd_t *tx_bd_base;121121+ cbd_t *dirty_tx; /* ring entries to be free()ed. */122122+ cbd_t *cur_rx;123123+ cbd_t *cur_tx;124124+ int tx_free;125125+ struct net_device_stats stats;126126+ struct timer_list phy_timer_list;127127+ const struct phy_info *phy;128128+ u32 msg_enable;129129+ struct mii_if_info mii_if;130130+ unsigned int last_mii_status;131131+ struct fs_enet_mii_bus *mii_bus;132132+ int interrupt;133133+134134+ int duplex, speed; /* current settings */135135+136136+ /* event masks */137137+ u32 ev_napi_rx; /* mask of NAPI rx events */138138+ u32 ev_rx; /* rx event mask */139139+ u32 ev_tx; /* tx event mask */140140+ u32 ev_err; /* error event mask */141141+142142+ u16 bd_rx_empty; /* mask of BD rx empty */143143+ u16 bd_rx_err; /* mask of BD rx errors */144144+145145+ union {146146+ struct {147147+ int idx; /* FEC1 = 0, FEC2 = 1 */148148+ void *fecp; /* hw registers */149149+ u32 hthi, htlo; /* state for multicast */150150+ } fec;151151+152152+ struct {153153+ int idx; /* FCC1-3 = 0-2 */154154+ void *fccp; /* hw registers */155155+ void *ep; /* parameter ram */156156+ void *fcccp; /* hw registers cont. */157157+ void *mem; /* FCC DPRAM */158158+ u32 gaddrh, gaddrl; /* group address */159159+ } fcc;160160+161161+ struct {162162+ int idx; /* FEC1 = 0, FEC2 = 1 */163163+ void *sccp; /* hw registers */164164+ void *ep; /* parameter ram */165165+ u32 hthi, htlo; /* state for multicast */166166+ } scc;167167+168168+ };169169+};170170+171171+/***************************************************************************/172172+173173+int fs_mii_read(struct net_device *dev, int phy_id, int location);174174+void fs_mii_write(struct net_device *dev, int phy_id, int location, int value);175175+176176+void fs_mii_startup(struct net_device *dev);177177+void fs_mii_shutdown(struct net_device *dev);178178+void fs_mii_ack_int(struct net_device *dev);179179+180180+void fs_mii_link_status_change_check(struct net_device *dev, int init_media);181181+182182+void fs_init_bds(struct net_device *dev);183183+void fs_cleanup_bds(struct net_device *dev);184184+185185+/***************************************************************************/186186+187187+#define DRV_MODULE_NAME "fs_enet"188188+#define PFX DRV_MODULE_NAME ": "189189+#define DRV_MODULE_VERSION "1.0"190190+#define DRV_MODULE_RELDATE "Aug 8, 2005"191191+192192+/***************************************************************************/193193+194194+int fs_enet_platform_init(void);195195+void fs_enet_platform_cleanup(void);196196+197197+/***************************************************************************/198198+199199+/* buffer descriptor access macros */200200+201201+/* access macros */202202+#if defined(CONFIG_CPM1)203203+/* for a a CPM1 __raw_xxx's are sufficient */204204+#define __cbd_out32(addr, x) __raw_writel(x, addr)205205+#define __cbd_out16(addr, x) __raw_writew(x, addr)206206+#define __cbd_in32(addr) __raw_readl(addr)207207+#define __cbd_in16(addr) __raw_readw(addr)208208+#else209209+/* for others play it safe */210210+#define __cbd_out32(addr, x) out_be32(addr, x)211211+#define __cbd_out16(addr, x) out_be16(addr, x)212212+#define __cbd_in32(addr) in_be32(addr)213213+#define __cbd_in16(addr) in_be16(addr)214214+#endif215215+216216+/* write */217217+#define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc))218218+#define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen))219219+#define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr))220220+221221+/* read */222222+#define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc)223223+#define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen)224224+#define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr)225225+226226+/* set bits */227227+#define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc))228228+229229+/* clear bits */230230+#define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc))231231+232232+/*******************************************************************/233233+234234+extern const struct fs_ops fs_fec_ops;235235+extern const struct fs_ops fs_fcc_ops;236236+extern const struct fs_ops fs_scc_ops;237237+238238+/*******************************************************************/239239+240240+/* handy pointer to the immap */241241+extern void *fs_enet_immap;242242+243243+/*******************************************************************/244244+245245+#endif
+578
drivers/net/fs_enet/mac-fcc.c
···11+/*22+ * FCC driver for Motorola MPC82xx (PQ2).33+ *44+ * Copyright (c) 2003 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ *77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * This file is licensed under the terms of the GNU General Public License 1111+ * version 2. This program is licensed "as is" without any warranty of any 1212+ * kind, whether express or implied.1313+ */1414+1515+#include <linux/config.h>1616+#include <linux/module.h>1717+#include <linux/kernel.h>1818+#include <linux/types.h>1919+#include <linux/sched.h>2020+#include <linux/string.h>2121+#include <linux/ptrace.h>2222+#include <linux/errno.h>2323+#include <linux/ioport.h>2424+#include <linux/slab.h>2525+#include <linux/interrupt.h>2626+#include <linux/pci.h>2727+#include <linux/init.h>2828+#include <linux/delay.h>2929+#include <linux/netdevice.h>3030+#include <linux/etherdevice.h>3131+#include <linux/skbuff.h>3232+#include <linux/spinlock.h>3333+#include <linux/mii.h>3434+#include <linux/ethtool.h>3535+#include <linux/bitops.h>3636+#include <linux/fs.h>3737+3838+#include <asm/immap_cpm2.h>3939+#include <asm/mpc8260.h>4040+#include <asm/cpm2.h>4141+4242+#include <asm/pgtable.h>4343+#include <asm/irq.h>4444+#include <asm/uaccess.h>4545+4646+#include "fs_enet.h"4747+4848+/*************************************************/4949+5050+/* FCC access macros */5151+5252+#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x)5353+#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x)5454+#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x)5555+#define __fcc_in32(addr) in_be32((unsigned *)addr)5656+#define __fcc_in16(addr) in_be16((unsigned short *)addr)5757+#define __fcc_in8(addr) in_8((unsigned char *)addr)5858+5959+/* parameter space */6060+6161+/* write, read, set bits, clear bits */6262+#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v))6363+#define R32(_p, _m) __fcc_in32(&(_p)->_m)6464+#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v))6565+#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v))6666+6767+#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v))6868+#define R16(_p, _m) __fcc_in16(&(_p)->_m)6969+#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v))7070+#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v))7171+7272+#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v))7373+#define R8(_p, _m) __fcc_in8(&(_p)->_m)7474+#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v))7575+#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v))7676+7777+/*************************************************/7878+7979+#define FCC_MAX_MULTICAST_ADDRS 648080+8181+#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))8282+#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))8383+#define mk_mii_end 08484+8585+#define MAX_CR_CMD_LOOPS 100008686+8787+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)8888+{8989+ const struct fs_platform_info *fpi = fep->fpi;9090+9191+ cpm2_map_t *immap = fs_enet_immap;9292+ cpm_cpm2_t *cpmp = &immap->im_cpm;9393+ u32 v;9494+ int i;9595+9696+ /* Currently I don't know what feature call will look like. But 9797+ I guess there'd be something like do_cpm_cmd() which will require page & sblock */9898+ v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);9999+ W32(cpmp, cp_cpcr, v | CPM_CR_FLG);100100+ for (i = 0; i < MAX_CR_CMD_LOOPS; i++)101101+ if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)102102+ break;103103+104104+ if (i >= MAX_CR_CMD_LOOPS) {105105+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",106106+ __FUNCTION__);107107+ return 1;108108+ }109109+110110+ return 0;111111+}112112+113113+static int do_pd_setup(struct fs_enet_private *fep)114114+{115115+ struct platform_device *pdev = to_platform_device(fep->dev);116116+ struct resource *r;117117+118118+ /* Fill out IRQ field */119119+ fep->interrupt = platform_get_irq(pdev, 0);120120+121121+ /* Attach the memory for the FCC Parameter RAM */122122+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");123123+ fep->fcc.ep = (void *)r->start;124124+125125+ if (fep->fcc.ep == NULL)126126+ return -EINVAL;127127+128128+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");129129+ fep->fcc.fccp = (void *)r->start;130130+131131+ if (fep->fcc.fccp == NULL)132132+ return -EINVAL;133133+134134+ fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;135135+136136+ if (fep->fcc.fcccp == NULL)137137+ return -EINVAL;138138+139139+ return 0;140140+}141141+142142+#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB)143143+#define FCC_RX_EVENT (FCC_ENET_RXF)144144+#define FCC_TX_EVENT (FCC_ENET_TXB)145145+#define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY)146146+147147+static int setup_data(struct net_device *dev)148148+{149149+ struct fs_enet_private *fep = netdev_priv(dev);150150+ const struct fs_platform_info *fpi = fep->fpi;151151+152152+ fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);153153+ if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */154154+ return -EINVAL;155155+156156+ fep->fcc.mem = (void *)fpi->mem_offset;157157+158158+ if (do_pd_setup(fep) != 0)159159+ return -EINVAL;160160+161161+ fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK;162162+ fep->ev_rx = FCC_RX_EVENT;163163+ fep->ev_tx = FCC_TX_EVENT;164164+ fep->ev_err = FCC_ERR_EVENT_MSK;165165+166166+ return 0;167167+}168168+169169+static int allocate_bd(struct net_device *dev)170170+{171171+ struct fs_enet_private *fep = netdev_priv(dev);172172+ const struct fs_platform_info *fpi = fep->fpi;173173+174174+ fep->ring_base = dma_alloc_coherent(fep->dev,175175+ (fpi->tx_ring + fpi->rx_ring) *176176+ sizeof(cbd_t), &fep->ring_mem_addr,177177+ GFP_KERNEL);178178+ if (fep->ring_base == NULL)179179+ return -ENOMEM;180180+181181+ return 0;182182+}183183+184184+static void free_bd(struct net_device *dev)185185+{186186+ struct fs_enet_private *fep = netdev_priv(dev);187187+ const struct fs_platform_info *fpi = fep->fpi;188188+189189+ if (fep->ring_base)190190+ dma_free_coherent(fep->dev,191191+ (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),192192+ fep->ring_base, fep->ring_mem_addr);193193+}194194+195195+static void cleanup_data(struct net_device *dev)196196+{197197+ /* nothing */198198+}199199+200200+static void set_promiscuous_mode(struct net_device *dev)201201+{202202+ struct fs_enet_private *fep = netdev_priv(dev);203203+ fcc_t *fccp = fep->fcc.fccp;204204+205205+ S32(fccp, fcc_fpsmr, FCC_PSMR_PRO);206206+}207207+208208+static void set_multicast_start(struct net_device *dev)209209+{210210+ struct fs_enet_private *fep = netdev_priv(dev);211211+ fcc_enet_t *ep = fep->fcc.ep;212212+213213+ W32(ep, fen_gaddrh, 0);214214+ W32(ep, fen_gaddrl, 0);215215+}216216+217217+static void set_multicast_one(struct net_device *dev, const u8 *mac)218218+{219219+ struct fs_enet_private *fep = netdev_priv(dev);220220+ fcc_enet_t *ep = fep->fcc.ep;221221+ u16 taddrh, taddrm, taddrl;222222+223223+ taddrh = ((u16)mac[5] << 8) | mac[4];224224+ taddrm = ((u16)mac[3] << 8) | mac[2];225225+ taddrl = ((u16)mac[1] << 8) | mac[0];226226+227227+ W16(ep, fen_taddrh, taddrh);228228+ W16(ep, fen_taddrm, taddrm);229229+ W16(ep, fen_taddrl, taddrl);230230+ fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);231231+}232232+233233+static void set_multicast_finish(struct net_device *dev)234234+{235235+ struct fs_enet_private *fep = netdev_priv(dev);236236+ fcc_t *fccp = fep->fcc.fccp;237237+ fcc_enet_t *ep = fep->fcc.ep;238238+239239+ /* clear promiscuous always */240240+ C32(fccp, fcc_fpsmr, FCC_PSMR_PRO);241241+242242+ /* if all multi or too many multicasts; just enable all */243243+ if ((dev->flags & IFF_ALLMULTI) != 0 ||244244+ dev->mc_count > FCC_MAX_MULTICAST_ADDRS) {245245+246246+ W32(ep, fen_gaddrh, 0xffffffff);247247+ W32(ep, fen_gaddrl, 0xffffffff);248248+ }249249+250250+ /* read back */251251+ fep->fcc.gaddrh = R32(ep, fen_gaddrh);252252+ fep->fcc.gaddrl = R32(ep, fen_gaddrl);253253+}254254+255255+static void set_multicast_list(struct net_device *dev)256256+{257257+ struct dev_mc_list *pmc;258258+259259+ if ((dev->flags & IFF_PROMISC) == 0) {260260+ set_multicast_start(dev);261261+ for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)262262+ set_multicast_one(dev, pmc->dmi_addr);263263+ set_multicast_finish(dev);264264+ } else265265+ set_promiscuous_mode(dev);266266+}267267+268268+static void restart(struct net_device *dev)269269+{270270+ struct fs_enet_private *fep = netdev_priv(dev);271271+ const struct fs_platform_info *fpi = fep->fpi;272272+ fcc_t *fccp = fep->fcc.fccp;273273+ fcc_c_t *fcccp = fep->fcc.fcccp;274274+ fcc_enet_t *ep = fep->fcc.ep;275275+ dma_addr_t rx_bd_base_phys, tx_bd_base_phys;276276+ u16 paddrh, paddrm, paddrl;277277+ u16 mem_addr;278278+ const unsigned char *mac;279279+ int i;280280+281281+ C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);282282+283283+ /* clear everything (slow & steady does it) */284284+ for (i = 0; i < sizeof(*ep); i++)285285+ __fcc_out8((char *)ep + i, 0);286286+287287+ /* get physical address */288288+ rx_bd_base_phys = fep->ring_mem_addr;289289+ tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;290290+291291+ /* point to bds */292292+ W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys);293293+ W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys);294294+295295+ /* Set maximum bytes per receive buffer.296296+ * It must be a multiple of 32.297297+ */298298+ W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE);299299+300300+ W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24);301301+ W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24);302302+303303+ /* Allocate space in the reserved FCC area of DPRAM for the304304+ * internal buffers. No one uses this space (yet), so we305305+ * can do this. Later, we will add resource management for306306+ * this area.307307+ */308308+309309+ mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */310310+311311+ W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff));312312+ W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff));313313+ W16(ep, fen_padptr, mem_addr + 64);314314+315315+ /* fill with special symbol... */316316+ memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);317317+318318+ W32(ep, fen_genfcc.fcc_rbptr, 0);319319+ W32(ep, fen_genfcc.fcc_tbptr, 0);320320+ W32(ep, fen_genfcc.fcc_rcrc, 0);321321+ W32(ep, fen_genfcc.fcc_tcrc, 0);322322+ W16(ep, fen_genfcc.fcc_res1, 0);323323+ W32(ep, fen_genfcc.fcc_res2, 0);324324+325325+ /* no CAM */326326+ W32(ep, fen_camptr, 0);327327+328328+ /* Set CRC preset and mask */329329+ W32(ep, fen_cmask, 0xdebb20e3);330330+ W32(ep, fen_cpres, 0xffffffff);331331+332332+ W32(ep, fen_crcec, 0); /* CRC Error counter */333333+ W32(ep, fen_alec, 0); /* alignment error counter */334334+ W32(ep, fen_disfc, 0); /* discard frame counter */335335+ W16(ep, fen_retlim, 15); /* Retry limit threshold */336336+ W16(ep, fen_pper, 0); /* Normal persistence */337337+338338+ /* set group address */339339+ W32(ep, fen_gaddrh, fep->fcc.gaddrh);340340+ W32(ep, fen_gaddrl, fep->fcc.gaddrh);341341+342342+ /* Clear hash filter tables */343343+ W32(ep, fen_iaddrh, 0);344344+ W32(ep, fen_iaddrl, 0);345345+346346+ /* Clear the Out-of-sequence TxBD */347347+ W16(ep, fen_tfcstat, 0);348348+ W16(ep, fen_tfclen, 0);349349+ W32(ep, fen_tfcptr, 0);350350+351351+ W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */352352+ W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */353353+354354+ /* set address */355355+ mac = dev->dev_addr;356356+ paddrh = ((u16)mac[5] << 8) | mac[4];357357+ paddrm = ((u16)mac[3] << 8) | mac[2];358358+ paddrl = ((u16)mac[1] << 8) | mac[0];359359+360360+ W16(ep, fen_paddrh, paddrh);361361+ W16(ep, fen_paddrm, paddrm);362362+ W16(ep, fen_paddrl, paddrl);363363+364364+ W16(ep, fen_taddrh, 0);365365+ W16(ep, fen_taddrm, 0);366366+ W16(ep, fen_taddrl, 0);367367+368368+ W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */369369+ W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */370370+371371+ /* Clear stat counters, in case we ever enable RMON */372372+ W32(ep, fen_octc, 0);373373+ W32(ep, fen_colc, 0);374374+ W32(ep, fen_broc, 0);375375+ W32(ep, fen_mulc, 0);376376+ W32(ep, fen_uspc, 0);377377+ W32(ep, fen_frgc, 0);378378+ W32(ep, fen_ospc, 0);379379+ W32(ep, fen_jbrc, 0);380380+ W32(ep, fen_p64c, 0);381381+ W32(ep, fen_p65c, 0);382382+ W32(ep, fen_p128c, 0);383383+ W32(ep, fen_p256c, 0);384384+ W32(ep, fen_p512c, 0);385385+ W32(ep, fen_p1024c, 0);386386+387387+ W16(ep, fen_rfthr, 0); /* Suggested by manual */388388+ W16(ep, fen_rfcnt, 0);389389+ W16(ep, fen_cftype, 0);390390+391391+ fs_init_bds(dev);392392+393393+ /* adjust to speed (for RMII mode) */394394+ if (fpi->use_rmii) {395395+ if (fep->speed == 100)396396+ C8(fcccp, fcc_gfemr, 0x20);397397+ else398398+ S8(fcccp, fcc_gfemr, 0x20);399399+ }400400+401401+ fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);402402+403403+ /* clear events */404404+ W16(fccp, fcc_fcce, 0xffff);405405+406406+ /* Enable interrupts we wish to service */407407+ W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB);408408+409409+ /* Set GFMR to enable Ethernet operating mode */410410+ W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET);411411+412412+ /* set sync/delimiters */413413+ W16(fccp, fcc_fdsr, 0xd555);414414+415415+ W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC);416416+417417+ if (fpi->use_rmii)418418+ S32(fccp, fcc_fpsmr, FCC_PSMR_RMII);419419+420420+ /* adjust to duplex mode */421421+ if (fep->duplex)422422+ S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);423423+ else424424+ C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);425425+426426+ S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);427427+}428428+429429+static void stop(struct net_device *dev)430430+{431431+ struct fs_enet_private *fep = netdev_priv(dev);432432+ fcc_t *fccp = fep->fcc.fccp;433433+434434+ /* stop ethernet */435435+ C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);436436+437437+ /* clear events */438438+ W16(fccp, fcc_fcce, 0xffff);439439+440440+ /* clear interrupt mask */441441+ W16(fccp, fcc_fccm, 0);442442+443443+ fs_cleanup_bds(dev);444444+}445445+446446+static void pre_request_irq(struct net_device *dev, int irq)447447+{448448+ /* nothing */449449+}450450+451451+static void post_free_irq(struct net_device *dev, int irq)452452+{453453+ /* nothing */454454+}455455+456456+static void napi_clear_rx_event(struct net_device *dev)457457+{458458+ struct fs_enet_private *fep = netdev_priv(dev);459459+ fcc_t *fccp = fep->fcc.fccp;460460+461461+ W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK);462462+}463463+464464+static void napi_enable_rx(struct net_device *dev)465465+{466466+ struct fs_enet_private *fep = netdev_priv(dev);467467+ fcc_t *fccp = fep->fcc.fccp;468468+469469+ S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);470470+}471471+472472+static void napi_disable_rx(struct net_device *dev)473473+{474474+ struct fs_enet_private *fep = netdev_priv(dev);475475+ fcc_t *fccp = fep->fcc.fccp;476476+477477+ C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);478478+}479479+480480+static void rx_bd_done(struct net_device *dev)481481+{482482+ /* nothing */483483+}484484+485485+static void tx_kickstart(struct net_device *dev)486486+{487487+ /* nothing */488488+}489489+490490+static u32 get_int_events(struct net_device *dev)491491+{492492+ struct fs_enet_private *fep = netdev_priv(dev);493493+ fcc_t *fccp = fep->fcc.fccp;494494+495495+ return (u32)R16(fccp, fcc_fcce);496496+}497497+498498+static void clear_int_events(struct net_device *dev, u32 int_events)499499+{500500+ struct fs_enet_private *fep = netdev_priv(dev);501501+ fcc_t *fccp = fep->fcc.fccp;502502+503503+ W16(fccp, fcc_fcce, int_events & 0xffff);504504+}505505+506506+static void ev_error(struct net_device *dev, u32 int_events)507507+{508508+ printk(KERN_WARNING DRV_MODULE_NAME509509+ ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);510510+}511511+512512+int get_regs(struct net_device *dev, void *p, int *sizep)513513+{514514+ struct fs_enet_private *fep = netdev_priv(dev);515515+516516+ if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))517517+ return -EINVAL;518518+519519+ memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));520520+ p = (char *)p + sizeof(fcc_t);521521+522522+ memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));523523+ p = (char *)p + sizeof(fcc_c_t);524524+525525+ memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));526526+527527+ return 0;528528+}529529+530530+int get_regs_len(struct net_device *dev)531531+{532532+ return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);533533+}534534+535535+/* Some transmit errors cause the transmitter to shut536536+ * down. We now issue a restart transmit. Since the537537+ * errors close the BD and update the pointers, the restart538538+ * _should_ pick up without having to reset any of our539539+ * pointers either. Also, To workaround 8260 device erratum 540540+ * CPM37, we must disable and then re-enable the transmitter541541+ * following a Late Collision, Underrun, or Retry Limit error.542542+ */543543+void tx_restart(struct net_device *dev)544544+{545545+ struct fs_enet_private *fep = netdev_priv(dev);546546+ fcc_t *fccp = fep->fcc.fccp;547547+548548+ C32(fccp, fcc_gfmr, FCC_GFMR_ENT);549549+ udelay(10);550550+ S32(fccp, fcc_gfmr, FCC_GFMR_ENT);551551+552552+ fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);553553+}554554+555555+/*************************************************************************/556556+557557+const struct fs_ops fs_fcc_ops = {558558+ .setup_data = setup_data,559559+ .cleanup_data = cleanup_data,560560+ .set_multicast_list = set_multicast_list,561561+ .restart = restart,562562+ .stop = stop,563563+ .pre_request_irq = pre_request_irq,564564+ .post_free_irq = post_free_irq,565565+ .napi_clear_rx_event = napi_clear_rx_event,566566+ .napi_enable_rx = napi_enable_rx,567567+ .napi_disable_rx = napi_disable_rx,568568+ .rx_bd_done = rx_bd_done,569569+ .tx_kickstart = tx_kickstart,570570+ .get_int_events = get_int_events,571571+ .clear_int_events = clear_int_events,572572+ .ev_error = ev_error,573573+ .get_regs = get_regs,574574+ .get_regs_len = get_regs_len,575575+ .tx_restart = tx_restart,576576+ .allocate_bd = allocate_bd,577577+ .free_bd = free_bd,578578+};
+653
drivers/net/fs_enet/mac-fec.c
···11+/*22+ * Freescale Ethernet controllers33+ *44+ * Copyright (c) 2005 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ *77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * This file is licensed under the terms of the GNU General Public License 1111+ * version 2. This program is licensed "as is" without any warranty of any 1212+ * kind, whether express or implied.1313+ */1414+1515+#include <linux/config.h>1616+#include <linux/module.h>1717+#include <linux/kernel.h>1818+#include <linux/types.h>1919+#include <linux/sched.h>2020+#include <linux/string.h>2121+#include <linux/ptrace.h>2222+#include <linux/errno.h>2323+#include <linux/ioport.h>2424+#include <linux/slab.h>2525+#include <linux/interrupt.h>2626+#include <linux/pci.h>2727+#include <linux/init.h>2828+#include <linux/delay.h>2929+#include <linux/netdevice.h>3030+#include <linux/etherdevice.h>3131+#include <linux/skbuff.h>3232+#include <linux/spinlock.h>3333+#include <linux/mii.h>3434+#include <linux/ethtool.h>3535+#include <linux/bitops.h>3636+#include <linux/fs.h>3737+3838+#include <asm/irq.h>3939+#include <asm/uaccess.h>4040+4141+#ifdef CONFIG_8xx4242+#include <asm/8xx_immap.h>4343+#include <asm/pgtable.h>4444+#include <asm/mpc8xx.h>4545+#include <asm/commproc.h>4646+#endif4747+4848+#include "fs_enet.h"4949+5050+/*************************************************/5151+5252+#if defined(CONFIG_CPM1)5353+/* for a CPM1 __raw_xxx's are sufficient */5454+#define __fs_out32(addr, x) __raw_writel(x, addr)5555+#define __fs_out16(addr, x) __raw_writew(x, addr)5656+#define __fs_in32(addr) __raw_readl(addr)5757+#define __fs_in16(addr) __raw_readw(addr)5858+#else5959+/* for others play it safe */6060+#define __fs_out32(addr, x) out_be32(addr, x)6161+#define __fs_out16(addr, x) out_be16(addr, x)6262+#define __fs_in32(addr) in_be32(addr)6363+#define __fs_in16(addr) in_be16(addr)6464+#endif6565+6666+/* write */6767+#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v))6868+6969+/* read */7070+#define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg)7171+7272+/* set bits */7373+#define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v))7474+7575+/* clear bits */7676+#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v))7777+7878+7979+/* CRC polynomium used by the FEC for the multicast group filtering */8080+#define FEC_CRC_POLY 0x04C11DB78181+8282+#define FEC_MAX_MULTICAST_ADDRS 648383+8484+/* Interrupt events/masks.8585+*/8686+#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */8787+#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */8888+#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */8989+#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */9090+#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */9191+#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */9292+#define FEC_ENET_RXF 0x02000000U /* Full frame received */9393+#define FEC_ENET_RXB 0x01000000U /* A buffer was received */9494+#define FEC_ENET_MII 0x00800000U /* MII interrupt */9595+#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */9696+9797+#define FEC_ECNTRL_PINMUX 0x000000049898+#define FEC_ECNTRL_ETHER_EN 0x000000029999+#define FEC_ECNTRL_RESET 0x00000001100100+101101+#define FEC_RCNTRL_BC_REJ 0x00000010102102+#define FEC_RCNTRL_PROM 0x00000008103103+#define FEC_RCNTRL_MII_MODE 0x00000004104104+#define FEC_RCNTRL_DRT 0x00000002105105+#define FEC_RCNTRL_LOOP 0x00000001106106+107107+#define FEC_TCNTRL_FDEN 0x00000004108108+#define FEC_TCNTRL_HBC 0x00000002109109+#define FEC_TCNTRL_GTS 0x00000001110110+111111+112112+/* Make MII read/write commands for the FEC.113113+*/114114+#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))115115+#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))116116+#define mk_mii_end 0117117+118118+#define FEC_MII_LOOPS 10000119119+120120+/*121121+ * Delay to wait for FEC reset command to complete (in us) 122122+ */123123+#define FEC_RESET_DELAY 50124124+125125+static int whack_reset(fec_t * fecp)126126+{127127+ int i;128128+129129+ FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET);130130+ for (i = 0; i < FEC_RESET_DELAY; i++) {131131+ if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0)132132+ return 0; /* OK */133133+ udelay(1);134134+ }135135+136136+ return -1;137137+}138138+139139+static int do_pd_setup(struct fs_enet_private *fep)140140+{141141+ struct platform_device *pdev = to_platform_device(fep->dev); 142142+ struct resource *r;143143+144144+ /* Fill out IRQ field */145145+ fep->interrupt = platform_get_irq_byname(pdev,"interrupt");146146+147147+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");148148+ fep->fec.fecp =(void*)r->start;149149+150150+ if(fep->fec.fecp == NULL)151151+ return -EINVAL;152152+153153+ return 0;154154+155155+}156156+157157+#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB)158158+#define FEC_RX_EVENT (FEC_ENET_RXF)159159+#define FEC_TX_EVENT (FEC_ENET_TXF)160160+#define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \161161+ FEC_ENET_BABT | FEC_ENET_EBERR)162162+163163+static int setup_data(struct net_device *dev)164164+{165165+ struct fs_enet_private *fep = netdev_priv(dev);166166+167167+ if (do_pd_setup(fep) != 0)168168+ return -EINVAL;169169+170170+ fep->fec.hthi = 0;171171+ fep->fec.htlo = 0;172172+173173+ fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK;174174+ fep->ev_rx = FEC_RX_EVENT;175175+ fep->ev_tx = FEC_TX_EVENT;176176+ fep->ev_err = FEC_ERR_EVENT_MSK;177177+178178+ return 0;179179+}180180+181181+static int allocate_bd(struct net_device *dev)182182+{183183+ struct fs_enet_private *fep = netdev_priv(dev);184184+ const struct fs_platform_info *fpi = fep->fpi;185185+186186+ fep->ring_base = dma_alloc_coherent(fep->dev,187187+ (fpi->tx_ring + fpi->rx_ring) *188188+ sizeof(cbd_t), &fep->ring_mem_addr,189189+ GFP_KERNEL);190190+ if (fep->ring_base == NULL)191191+ return -ENOMEM;192192+193193+ return 0;194194+}195195+196196+static void free_bd(struct net_device *dev)197197+{198198+ struct fs_enet_private *fep = netdev_priv(dev);199199+ const struct fs_platform_info *fpi = fep->fpi;200200+201201+ if(fep->ring_base)202202+ dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring)203203+ * sizeof(cbd_t),204204+ fep->ring_base,205205+ fep->ring_mem_addr);206206+}207207+208208+static void cleanup_data(struct net_device *dev)209209+{210210+ /* nothing */211211+}212212+213213+static void set_promiscuous_mode(struct net_device *dev)214214+{215215+ struct fs_enet_private *fep = netdev_priv(dev);216216+ fec_t *fecp = fep->fec.fecp;217217+218218+ FS(fecp, r_cntrl, FEC_RCNTRL_PROM);219219+}220220+221221+static void set_multicast_start(struct net_device *dev)222222+{223223+ struct fs_enet_private *fep = netdev_priv(dev);224224+225225+ fep->fec.hthi = 0;226226+ fep->fec.htlo = 0;227227+}228228+229229+static void set_multicast_one(struct net_device *dev, const u8 *mac)230230+{231231+ struct fs_enet_private *fep = netdev_priv(dev);232232+ int temp, hash_index, i, j;233233+ u32 crc, csrVal;234234+ u8 byte, msb;235235+236236+ crc = 0xffffffff;237237+ for (i = 0; i < 6; i++) {238238+ byte = mac[i];239239+ for (j = 0; j < 8; j++) {240240+ msb = crc >> 31;241241+ crc <<= 1;242242+ if (msb ^ (byte & 0x1))243243+ crc ^= FEC_CRC_POLY;244244+ byte >>= 1;245245+ }246246+ }247247+248248+ temp = (crc & 0x3f) >> 1;249249+ hash_index = ((temp & 0x01) << 4) |250250+ ((temp & 0x02) << 2) |251251+ ((temp & 0x04)) |252252+ ((temp & 0x08) >> 2) |253253+ ((temp & 0x10) >> 4);254254+ csrVal = 1 << hash_index;255255+ if (crc & 1)256256+ fep->fec.hthi |= csrVal;257257+ else258258+ fep->fec.htlo |= csrVal;259259+}260260+261261+static void set_multicast_finish(struct net_device *dev)262262+{263263+ struct fs_enet_private *fep = netdev_priv(dev);264264+ fec_t *fecp = fep->fec.fecp;265265+266266+ /* if all multi or too many multicasts; just enable all */267267+ if ((dev->flags & IFF_ALLMULTI) != 0 ||268268+ dev->mc_count > FEC_MAX_MULTICAST_ADDRS) {269269+ fep->fec.hthi = 0xffffffffU;270270+ fep->fec.htlo = 0xffffffffU;271271+ }272272+273273+ FC(fecp, r_cntrl, FEC_RCNTRL_PROM);274274+ FW(fecp, hash_table_high, fep->fec.hthi);275275+ FW(fecp, hash_table_low, fep->fec.htlo);276276+}277277+278278+static void set_multicast_list(struct net_device *dev)279279+{280280+ struct dev_mc_list *pmc;281281+282282+ if ((dev->flags & IFF_PROMISC) == 0) {283283+ set_multicast_start(dev);284284+ for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)285285+ set_multicast_one(dev, pmc->dmi_addr);286286+ set_multicast_finish(dev);287287+ } else288288+ set_promiscuous_mode(dev);289289+}290290+291291+static void restart(struct net_device *dev)292292+{293293+#ifdef CONFIG_DUET294294+ immap_t *immap = fs_enet_immap;295295+ u32 cptr;296296+#endif297297+ struct fs_enet_private *fep = netdev_priv(dev);298298+ fec_t *fecp = fep->fec.fecp;299299+ const struct fs_platform_info *fpi = fep->fpi;300300+ dma_addr_t rx_bd_base_phys, tx_bd_base_phys;301301+ int r;302302+ u32 addrhi, addrlo;303303+304304+ r = whack_reset(fep->fec.fecp);305305+ if (r != 0)306306+ printk(KERN_ERR DRV_MODULE_NAME307307+ ": %s FEC Reset FAILED!\n", dev->name);308308+309309+ /*310310+ * Set station address. 311311+ */312312+ addrhi = ((u32) dev->dev_addr[0] << 24) |313313+ ((u32) dev->dev_addr[1] << 16) |314314+ ((u32) dev->dev_addr[2] << 8) |315315+ (u32) dev->dev_addr[3];316316+ addrlo = ((u32) dev->dev_addr[4] << 24) |317317+ ((u32) dev->dev_addr[5] << 16);318318+ FW(fecp, addr_low, addrhi);319319+ FW(fecp, addr_high, addrlo);320320+321321+ /*322322+ * Reset all multicast. 323323+ */324324+ FW(fecp, hash_table_high, fep->fec.hthi);325325+ FW(fecp, hash_table_low, fep->fec.htlo);326326+327327+ /*328328+ * Set maximum receive buffer size. 329329+ */330330+ FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);331331+ FW(fecp, r_hash, PKT_MAXBUF_SIZE);332332+333333+ /* get physical address */334334+ rx_bd_base_phys = fep->ring_mem_addr;335335+ tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;336336+337337+ /*338338+ * Set receive and transmit descriptor base. 339339+ */340340+ FW(fecp, r_des_start, rx_bd_base_phys);341341+ FW(fecp, x_des_start, tx_bd_base_phys);342342+343343+ fs_init_bds(dev);344344+345345+ /*346346+ * Enable big endian and don't care about SDMA FC. 347347+ */348348+ FW(fecp, fun_code, 0x78000000);349349+350350+ /*351351+ * Set MII speed. 352352+ */353353+ FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed);354354+355355+ /*356356+ * Clear any outstanding interrupt. 357357+ */358358+ FW(fecp, ievent, 0xffc0);359359+ FW(fecp, ivec, (fep->interrupt / 2) << 29);360360+361361+362362+ /*363363+ * adjust to speed (only for DUET & RMII) 364364+ */365365+#ifdef CONFIG_DUET366366+ if (fpi->use_rmii) {367367+ cptr = in_be32(&immap->im_cpm.cp_cptr);368368+ switch (fs_get_fec_index(fpi->fs_no)) {369369+ case 0:370370+ cptr |= 0x100;371371+ if (fep->speed == 10)372372+ cptr |= 0x0000010;373373+ else if (fep->speed == 100)374374+ cptr &= ~0x0000010;375375+ break;376376+ case 1:377377+ cptr |= 0x80;378378+ if (fep->speed == 10)379379+ cptr |= 0x0000008;380380+ else if (fep->speed == 100)381381+ cptr &= ~0x0000008;382382+ break;383383+ default:384384+ BUG(); /* should never happen */385385+ break;386386+ }387387+ out_be32(&immap->im_cpm.cp_cptr, cptr);388388+ }389389+#endif390390+391391+ FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */392392+ /*393393+ * adjust to duplex mode 394394+ */395395+ if (fep->duplex) {396396+ FC(fecp, r_cntrl, FEC_RCNTRL_DRT);397397+ FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */398398+ } else {399399+ FS(fecp, r_cntrl, FEC_RCNTRL_DRT);400400+ FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */401401+ }402402+403403+ /*404404+ * Enable interrupts we wish to service. 405405+ */406406+ FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB |407407+ FEC_ENET_RXF | FEC_ENET_RXB);408408+409409+ /*410410+ * And last, enable the transmit and receive processing. 411411+ */412412+ FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);413413+ FW(fecp, r_des_active, 0x01000000);414414+}415415+416416+static void stop(struct net_device *dev)417417+{418418+ struct fs_enet_private *fep = netdev_priv(dev);419419+ fec_t *fecp = fep->fec.fecp;420420+ struct fs_enet_mii_bus *bus = fep->mii_bus;421421+ const struct fs_mii_bus_info *bi = bus->bus_info;422422+ int i;423423+424424+ if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0)425425+ return; /* already down */426426+427427+ FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */428428+ for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) &&429429+ i < FEC_RESET_DELAY; i++)430430+ udelay(1);431431+432432+ if (i == FEC_RESET_DELAY)433433+ printk(KERN_WARNING DRV_MODULE_NAME434434+ ": %s FEC timeout on graceful transmit stop\n",435435+ dev->name);436436+ /*437437+ * Disable FEC. Let only MII interrupts. 438438+ */439439+ FW(fecp, imask, 0);440440+ FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN);441441+442442+ fs_cleanup_bds(dev);443443+444444+ /* shut down FEC1? that's where the mii bus is */445445+ if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) {446446+ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */447447+ FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);448448+ FW(fecp, ievent, FEC_ENET_MII);449449+ FW(fecp, mii_speed, bus->fec.mii_speed);450450+ }451451+}452452+453453+static void pre_request_irq(struct net_device *dev, int irq)454454+{455455+ immap_t *immap = fs_enet_immap;456456+ u32 siel;457457+458458+ /* SIU interrupt */459459+ if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {460460+461461+ siel = in_be32(&immap->im_siu_conf.sc_siel);462462+ if ((irq & 1) == 0)463463+ siel |= (0x80000000 >> irq);464464+ else465465+ siel &= ~(0x80000000 >> (irq & ~1));466466+ out_be32(&immap->im_siu_conf.sc_siel, siel);467467+ }468468+}469469+470470+static void post_free_irq(struct net_device *dev, int irq)471471+{472472+ /* nothing */473473+}474474+475475+static void napi_clear_rx_event(struct net_device *dev)476476+{477477+ struct fs_enet_private *fep = netdev_priv(dev);478478+ fec_t *fecp = fep->fec.fecp;479479+480480+ FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);481481+}482482+483483+static void napi_enable_rx(struct net_device *dev)484484+{485485+ struct fs_enet_private *fep = netdev_priv(dev);486486+ fec_t *fecp = fep->fec.fecp;487487+488488+ FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);489489+}490490+491491+static void napi_disable_rx(struct net_device *dev)492492+{493493+ struct fs_enet_private *fep = netdev_priv(dev);494494+ fec_t *fecp = fep->fec.fecp;495495+496496+ FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);497497+}498498+499499+static void rx_bd_done(struct net_device *dev)500500+{501501+ struct fs_enet_private *fep = netdev_priv(dev);502502+ fec_t *fecp = fep->fec.fecp;503503+504504+ FW(fecp, r_des_active, 0x01000000);505505+}506506+507507+static void tx_kickstart(struct net_device *dev)508508+{509509+ struct fs_enet_private *fep = netdev_priv(dev);510510+ fec_t *fecp = fep->fec.fecp;511511+512512+ FW(fecp, x_des_active, 0x01000000);513513+}514514+515515+static u32 get_int_events(struct net_device *dev)516516+{517517+ struct fs_enet_private *fep = netdev_priv(dev);518518+ fec_t *fecp = fep->fec.fecp;519519+520520+ return FR(fecp, ievent) & FR(fecp, imask);521521+}522522+523523+static void clear_int_events(struct net_device *dev, u32 int_events)524524+{525525+ struct fs_enet_private *fep = netdev_priv(dev);526526+ fec_t *fecp = fep->fec.fecp;527527+528528+ FW(fecp, ievent, int_events);529529+}530530+531531+static void ev_error(struct net_device *dev, u32 int_events)532532+{533533+ printk(KERN_WARNING DRV_MODULE_NAME534534+ ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);535535+}536536+537537+int get_regs(struct net_device *dev, void *p, int *sizep)538538+{539539+ struct fs_enet_private *fep = netdev_priv(dev);540540+541541+ if (*sizep < sizeof(fec_t))542542+ return -EINVAL;543543+544544+ memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t));545545+546546+ return 0;547547+}548548+549549+int get_regs_len(struct net_device *dev)550550+{551551+ return sizeof(fec_t);552552+}553553+554554+void tx_restart(struct net_device *dev)555555+{556556+ /* nothing */557557+}558558+559559+/*************************************************************************/560560+561561+const struct fs_ops fs_fec_ops = {562562+ .setup_data = setup_data,563563+ .cleanup_data = cleanup_data,564564+ .set_multicast_list = set_multicast_list,565565+ .restart = restart,566566+ .stop = stop,567567+ .pre_request_irq = pre_request_irq,568568+ .post_free_irq = post_free_irq,569569+ .napi_clear_rx_event = napi_clear_rx_event,570570+ .napi_enable_rx = napi_enable_rx,571571+ .napi_disable_rx = napi_disable_rx,572572+ .rx_bd_done = rx_bd_done,573573+ .tx_kickstart = tx_kickstart,574574+ .get_int_events = get_int_events,575575+ .clear_int_events = clear_int_events,576576+ .ev_error = ev_error,577577+ .get_regs = get_regs,578578+ .get_regs_len = get_regs_len,579579+ .tx_restart = tx_restart,580580+ .allocate_bd = allocate_bd,581581+ .free_bd = free_bd,582582+};583583+584584+/***********************************************************************/585585+586586+static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)587587+{588588+ fec_t *fecp = bus->fec.fecp;589589+ int i, ret = -1;590590+591591+ if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)592592+ BUG();593593+594594+ /* Add PHY address to register command. */595595+ FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));596596+597597+ for (i = 0; i < FEC_MII_LOOPS; i++)598598+ if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)599599+ break;600600+601601+ if (i < FEC_MII_LOOPS) {602602+ FW(fecp, ievent, FEC_ENET_MII);603603+ ret = FR(fecp, mii_data) & 0xffff;604604+ }605605+606606+ return ret;607607+}608608+609609+static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value)610610+{611611+ fec_t *fecp = bus->fec.fecp;612612+ int i;613613+614614+ /* this must never happen */615615+ if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)616616+ BUG();617617+618618+ /* Add PHY address to register command. */619619+ FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));620620+621621+ for (i = 0; i < FEC_MII_LOOPS; i++)622622+ if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)623623+ break;624624+625625+ if (i < FEC_MII_LOOPS)626626+ FW(fecp, ievent, FEC_ENET_MII);627627+}628628+629629+int fs_mii_fec_init(struct fs_enet_mii_bus *bus)630630+{631631+ bd_t *bd = (bd_t *)__res;632632+ const struct fs_mii_bus_info *bi = bus->bus_info;633633+ fec_t *fecp;634634+635635+ if (bi->id != 0)636636+ return -1;637637+638638+ bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec;639639+ bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2)640640+ & 0x3F) << 1;641641+642642+ fecp = bus->fec.fecp;643643+644644+ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */645645+ FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);646646+ FW(fecp, ievent, FEC_ENET_MII);647647+ FW(fecp, mii_speed, bus->fec.mii_speed);648648+649649+ bus->mii_read = mii_read;650650+ bus->mii_write = mii_write;651651+652652+ return 0;653653+}
+524
drivers/net/fs_enet/mac-scc.c
···11+/*22+ * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx.33+ *44+ * Copyright (c) 2003 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ * 77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * This file is licensed under the terms of the GNU General Public License 1111+ * version 2. This program is licensed "as is" without any warranty of any 1212+ * kind, whether express or implied.1313+ */1414+1515+#include <linux/config.h>1616+#include <linux/module.h>1717+#include <linux/kernel.h>1818+#include <linux/types.h>1919+#include <linux/sched.h>2020+#include <linux/string.h>2121+#include <linux/ptrace.h>2222+#include <linux/errno.h>2323+#include <linux/ioport.h>2424+#include <linux/slab.h>2525+#include <linux/interrupt.h>2626+#include <linux/pci.h>2727+#include <linux/init.h>2828+#include <linux/delay.h>2929+#include <linux/netdevice.h>3030+#include <linux/etherdevice.h>3131+#include <linux/skbuff.h>3232+#include <linux/spinlock.h>3333+#include <linux/mii.h>3434+#include <linux/ethtool.h>3535+#include <linux/bitops.h>3636+#include <linux/fs.h>3737+3838+#include <asm/irq.h>3939+#include <asm/uaccess.h>4040+4141+#ifdef CONFIG_8xx4242+#include <asm/8xx_immap.h>4343+#include <asm/pgtable.h>4444+#include <asm/mpc8xx.h>4545+#include <asm/commproc.h>4646+#endif4747+4848+#include "fs_enet.h"4949+5050+/*************************************************/5151+5252+#if defined(CONFIG_CPM1)5353+/* for a 8xx __raw_xxx's are sufficient */5454+#define __fs_out32(addr, x) __raw_writel(x, addr)5555+#define __fs_out16(addr, x) __raw_writew(x, addr)5656+#define __fs_out8(addr, x) __raw_writeb(x, addr)5757+#define __fs_in32(addr) __raw_readl(addr)5858+#define __fs_in16(addr) __raw_readw(addr)5959+#define __fs_in8(addr) __raw_readb(addr)6060+#else6161+/* for others play it safe */6262+#define __fs_out32(addr, x) out_be32(addr, x)6363+#define __fs_out16(addr, x) out_be16(addr, x)6464+#define __fs_in32(addr) in_be32(addr)6565+#define __fs_in16(addr) in_be16(addr)6666+#endif6767+6868+/* write, read, set bits, clear bits */6969+#define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v))7070+#define R32(_p, _m) __fs_in32(&(_p)->_m)7171+#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v))7272+#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v))7373+7474+#define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v))7575+#define R16(_p, _m) __fs_in16(&(_p)->_m)7676+#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v))7777+#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v))7878+7979+#define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v))8080+#define R8(_p, _m) __fs_in8(&(_p)->_m)8181+#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v))8282+#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v))8383+8484+#define SCC_MAX_MULTICAST_ADDRS 648585+8686+/*8787+ * Delay to wait for SCC reset command to complete (in us) 8888+ */8989+#define SCC_RESET_DELAY 509090+#define MAX_CR_CMD_LOOPS 100009191+9292+static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)9393+{9494+ cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;9595+ u32 v, ch;9696+ int i = 0;9797+9898+ ch = fep->scc.idx << 2;9999+ v = mk_cr_cmd(ch, op);100100+ W16(cpmp, cp_cpcr, v | CPM_CR_FLG);101101+ for (i = 0; i < MAX_CR_CMD_LOOPS; i++)102102+ if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)103103+ break;104104+105105+ if (i >= MAX_CR_CMD_LOOPS) {106106+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",107107+ __FUNCTION__);108108+ return 1;109109+ }110110+ return 0;111111+}112112+113113+static int do_pd_setup(struct fs_enet_private *fep)114114+{115115+ struct platform_device *pdev = to_platform_device(fep->dev);116116+ struct resource *r;117117+118118+ /* Fill out IRQ field */119119+ fep->interrupt = platform_get_irq_byname(pdev, "interrupt");120120+121121+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");122122+ fep->scc.sccp = (void *)r->start;123123+124124+ if (fep->scc.sccp == NULL)125125+ return -EINVAL;126126+127127+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram");128128+ fep->scc.ep = (void *)r->start;129129+130130+ if (fep->scc.ep == NULL)131131+ return -EINVAL;132132+133133+ return 0;134134+}135135+136136+#define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB)137137+#define SCC_RX_EVENT (SCCE_ENET_RXF)138138+#define SCC_TX_EVENT (SCCE_ENET_TXB)139139+#define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY)140140+141141+static int setup_data(struct net_device *dev)142142+{143143+ struct fs_enet_private *fep = netdev_priv(dev);144144+ const struct fs_platform_info *fpi = fep->fpi;145145+146146+ fep->scc.idx = fs_get_scc_index(fpi->fs_no);147147+ if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */148148+ return -EINVAL;149149+150150+ do_pd_setup(fep);151151+152152+ fep->scc.hthi = 0;153153+ fep->scc.htlo = 0;154154+155155+ fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;156156+ fep->ev_rx = SCC_RX_EVENT;157157+ fep->ev_tx = SCC_TX_EVENT;158158+ fep->ev_err = SCC_ERR_EVENT_MSK;159159+160160+ return 0;161161+}162162+163163+static int allocate_bd(struct net_device *dev)164164+{165165+ struct fs_enet_private *fep = netdev_priv(dev);166166+ const struct fs_platform_info *fpi = fep->fpi;167167+168168+ fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) *169169+ sizeof(cbd_t), 8);170170+ if (IS_DPERR(fep->ring_mem_addr))171171+ return -ENOMEM;172172+173173+ fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);174174+175175+ return 0;176176+}177177+178178+static void free_bd(struct net_device *dev)179179+{180180+ struct fs_enet_private *fep = netdev_priv(dev);181181+182182+ if (fep->ring_base)183183+ cpm_dpfree(fep->ring_mem_addr);184184+}185185+186186+static void cleanup_data(struct net_device *dev)187187+{188188+ /* nothing */189189+}190190+191191+static void set_promiscuous_mode(struct net_device *dev)192192+{ 193193+ struct fs_enet_private *fep = netdev_priv(dev);194194+ scc_t *sccp = fep->scc.sccp;195195+196196+ S16(sccp, scc_psmr, SCC_PSMR_PRO);197197+}198198+199199+static void set_multicast_start(struct net_device *dev)200200+{201201+ struct fs_enet_private *fep = netdev_priv(dev);202202+ scc_enet_t *ep = fep->scc.ep;203203+204204+ W16(ep, sen_gaddr1, 0);205205+ W16(ep, sen_gaddr2, 0);206206+ W16(ep, sen_gaddr3, 0);207207+ W16(ep, sen_gaddr4, 0);208208+}209209+210210+static void set_multicast_one(struct net_device *dev, const u8 * mac)211211+{212212+ struct fs_enet_private *fep = netdev_priv(dev);213213+ scc_enet_t *ep = fep->scc.ep;214214+ u16 taddrh, taddrm, taddrl;215215+216216+ taddrh = ((u16) mac[5] << 8) | mac[4];217217+ taddrm = ((u16) mac[3] << 8) | mac[2];218218+ taddrl = ((u16) mac[1] << 8) | mac[0];219219+220220+ W16(ep, sen_taddrh, taddrh);221221+ W16(ep, sen_taddrm, taddrm);222222+ W16(ep, sen_taddrl, taddrl);223223+ scc_cr_cmd(fep, CPM_CR_SET_GADDR);224224+}225225+226226+static void set_multicast_finish(struct net_device *dev)227227+{228228+ struct fs_enet_private *fep = netdev_priv(dev);229229+ scc_t *sccp = fep->scc.sccp;230230+ scc_enet_t *ep = fep->scc.ep;231231+232232+ /* clear promiscuous always */233233+ C16(sccp, scc_psmr, SCC_PSMR_PRO);234234+235235+ /* if all multi or too many multicasts; just enable all */236236+ if ((dev->flags & IFF_ALLMULTI) != 0 ||237237+ dev->mc_count > SCC_MAX_MULTICAST_ADDRS) {238238+239239+ W16(ep, sen_gaddr1, 0xffff);240240+ W16(ep, sen_gaddr2, 0xffff);241241+ W16(ep, sen_gaddr3, 0xffff);242242+ W16(ep, sen_gaddr4, 0xffff);243243+ }244244+}245245+246246+static void set_multicast_list(struct net_device *dev)247247+{248248+ struct dev_mc_list *pmc;249249+250250+ if ((dev->flags & IFF_PROMISC) == 0) {251251+ set_multicast_start(dev);252252+ for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)253253+ set_multicast_one(dev, pmc->dmi_addr);254254+ set_multicast_finish(dev);255255+ } else256256+ set_promiscuous_mode(dev);257257+}258258+259259+/*260260+ * This function is called to start or restart the FEC during a link261261+ * change. This only happens when switching between half and full262262+ * duplex.263263+ */264264+static void restart(struct net_device *dev)265265+{266266+ struct fs_enet_private *fep = netdev_priv(dev);267267+ scc_t *sccp = fep->scc.sccp;268268+ scc_enet_t *ep = fep->scc.ep;269269+ const struct fs_platform_info *fpi = fep->fpi;270270+ u16 paddrh, paddrm, paddrl;271271+ const unsigned char *mac;272272+ int i;273273+274274+ C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);275275+276276+ /* clear everything (slow & steady does it) */277277+ for (i = 0; i < sizeof(*ep); i++)278278+ __fs_out8((char *)ep + i, 0);279279+280280+ /* point to bds */281281+ W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr);282282+ W16(ep, sen_genscc.scc_tbase,283283+ fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring);284284+285285+ /* Initialize function code registers for big-endian.286286+ */287287+ W8(ep, sen_genscc.scc_rfcr, SCC_EB);288288+ W8(ep, sen_genscc.scc_tfcr, SCC_EB);289289+290290+ /* Set maximum bytes per receive buffer.291291+ * This appears to be an Ethernet frame size, not the buffer292292+ * fragment size. It must be a multiple of four.293293+ */294294+ W16(ep, sen_genscc.scc_mrblr, 0x5f0);295295+296296+ /* Set CRC preset and mask.297297+ */298298+ W32(ep, sen_cpres, 0xffffffff);299299+ W32(ep, sen_cmask, 0xdebb20e3);300300+301301+ W32(ep, sen_crcec, 0); /* CRC Error counter */302302+ W32(ep, sen_alec, 0); /* alignment error counter */303303+ W32(ep, sen_disfc, 0); /* discard frame counter */304304+305305+ W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */306306+ W16(ep, sen_retlim, 15); /* Retry limit threshold */307307+308308+ W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */309309+310310+ W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */311311+312312+ W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */313313+ W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */314314+315315+ /* Clear hash tables.316316+ */317317+ W16(ep, sen_gaddr1, 0);318318+ W16(ep, sen_gaddr2, 0);319319+ W16(ep, sen_gaddr3, 0);320320+ W16(ep, sen_gaddr4, 0);321321+ W16(ep, sen_iaddr1, 0);322322+ W16(ep, sen_iaddr2, 0);323323+ W16(ep, sen_iaddr3, 0);324324+ W16(ep, sen_iaddr4, 0);325325+326326+ /* set address 327327+ */328328+ mac = dev->dev_addr;329329+ paddrh = ((u16) mac[5] << 8) | mac[4];330330+ paddrm = ((u16) mac[3] << 8) | mac[2];331331+ paddrl = ((u16) mac[1] << 8) | mac[0];332332+333333+ W16(ep, sen_paddrh, paddrh);334334+ W16(ep, sen_paddrm, paddrm);335335+ W16(ep, sen_paddrl, paddrl);336336+337337+ W16(ep, sen_pper, 0);338338+ W16(ep, sen_taddrl, 0);339339+ W16(ep, sen_taddrm, 0);340340+ W16(ep, sen_taddrh, 0);341341+342342+ fs_init_bds(dev);343343+344344+ scc_cr_cmd(fep, CPM_CR_INIT_TRX);345345+346346+ W16(sccp, scc_scce, 0xffff);347347+348348+ /* Enable interrupts we wish to service. 349349+ */350350+ W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);351351+352352+ /* Set GSMR_H to enable all normal operating modes.353353+ * Set GSMR_L to enable Ethernet to MC68160.354354+ */355355+ W32(sccp, scc_gsmrh, 0);356356+ W32(sccp, scc_gsmrl,357357+ SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 |358358+ SCC_GSMRL_MODE_ENET);359359+360360+ /* Set sync/delimiters.361361+ */362362+ W16(sccp, scc_dsr, 0xd555);363363+364364+ /* Set processing mode. Use Ethernet CRC, catch broadcast, and365365+ * start frame search 22 bit times after RENA.366366+ */367367+ W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22);368368+369369+ /* Set full duplex mode if needed */370370+ if (fep->duplex)371371+ S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE);372372+373373+ S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);374374+}375375+376376+static void stop(struct net_device *dev) 377377+{378378+ struct fs_enet_private *fep = netdev_priv(dev);379379+ scc_t *sccp = fep->scc.sccp;380380+ int i;381381+382382+ for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++)383383+ udelay(1);384384+385385+ if (i == SCC_RESET_DELAY)386386+ printk(KERN_WARNING DRV_MODULE_NAME387387+ ": %s SCC timeout on graceful transmit stop\n",388388+ dev->name);389389+390390+ W16(sccp, scc_sccm, 0);391391+ C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);392392+393393+ fs_cleanup_bds(dev);394394+}395395+396396+static void pre_request_irq(struct net_device *dev, int irq)397397+{398398+ immap_t *immap = fs_enet_immap;399399+ u32 siel;400400+401401+ /* SIU interrupt */402402+ if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {403403+404404+ siel = in_be32(&immap->im_siu_conf.sc_siel);405405+ if ((irq & 1) == 0)406406+ siel |= (0x80000000 >> irq);407407+ else408408+ siel &= ~(0x80000000 >> (irq & ~1));409409+ out_be32(&immap->im_siu_conf.sc_siel, siel);410410+ }411411+}412412+413413+static void post_free_irq(struct net_device *dev, int irq)414414+{415415+ /* nothing */416416+}417417+418418+static void napi_clear_rx_event(struct net_device *dev)419419+{420420+ struct fs_enet_private *fep = netdev_priv(dev);421421+ scc_t *sccp = fep->scc.sccp;422422+423423+ W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK);424424+}425425+426426+static void napi_enable_rx(struct net_device *dev)427427+{428428+ struct fs_enet_private *fep = netdev_priv(dev);429429+ scc_t *sccp = fep->scc.sccp;430430+431431+ S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);432432+}433433+434434+static void napi_disable_rx(struct net_device *dev)435435+{436436+ struct fs_enet_private *fep = netdev_priv(dev);437437+ scc_t *sccp = fep->scc.sccp;438438+439439+ C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);440440+}441441+442442+static void rx_bd_done(struct net_device *dev)443443+{444444+ /* nothing */445445+}446446+447447+static void tx_kickstart(struct net_device *dev)448448+{449449+ /* nothing */450450+}451451+452452+static u32 get_int_events(struct net_device *dev)453453+{454454+ struct fs_enet_private *fep = netdev_priv(dev);455455+ scc_t *sccp = fep->scc.sccp;456456+457457+ return (u32) R16(sccp, scc_scce);458458+}459459+460460+static void clear_int_events(struct net_device *dev, u32 int_events)461461+{462462+ struct fs_enet_private *fep = netdev_priv(dev);463463+ scc_t *sccp = fep->scc.sccp;464464+465465+ W16(sccp, scc_scce, int_events & 0xffff);466466+}467467+468468+static void ev_error(struct net_device *dev, u32 int_events)469469+{470470+ printk(KERN_WARNING DRV_MODULE_NAME471471+ ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events);472472+}473473+474474+static int get_regs(struct net_device *dev, void *p, int *sizep)475475+{476476+ struct fs_enet_private *fep = netdev_priv(dev);477477+478478+ if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t))479479+ return -EINVAL;480480+481481+ memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t));482482+ p = (char *)p + sizeof(scc_t);483483+484484+ memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t));485485+486486+ return 0;487487+}488488+489489+static int get_regs_len(struct net_device *dev)490490+{491491+ return sizeof(scc_t) + sizeof(scc_enet_t);492492+}493493+494494+static void tx_restart(struct net_device *dev)495495+{496496+ struct fs_enet_private *fep = netdev_priv(dev);497497+498498+ scc_cr_cmd(fep, CPM_CR_RESTART_TX);499499+}500500+501501+/*************************************************************************/502502+503503+const struct fs_ops fs_scc_ops = {504504+ .setup_data = setup_data,505505+ .cleanup_data = cleanup_data,506506+ .set_multicast_list = set_multicast_list,507507+ .restart = restart,508508+ .stop = stop,509509+ .pre_request_irq = pre_request_irq,510510+ .post_free_irq = post_free_irq,511511+ .napi_clear_rx_event = napi_clear_rx_event,512512+ .napi_enable_rx = napi_enable_rx,513513+ .napi_disable_rx = napi_disable_rx,514514+ .rx_bd_done = rx_bd_done,515515+ .tx_kickstart = tx_kickstart,516516+ .get_int_events = get_int_events,517517+ .clear_int_events = clear_int_events,518518+ .ev_error = ev_error,519519+ .get_regs = get_regs,520520+ .get_regs_len = get_regs_len,521521+ .tx_restart = tx_restart,522522+ .allocate_bd = allocate_bd,523523+ .free_bd = free_bd,524524+};
+405
drivers/net/fs_enet/mii-bitbang.c
···11+/*22+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.33+ *44+ * Copyright (c) 2003 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ * 77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * This file is licensed under the terms of the GNU General Public License 1111+ * version 2. This program is licensed "as is" without any warranty of any 1212+ * kind, whether express or implied.1313+ */1414+1515+1616+#include <linux/config.h>1717+#include <linux/module.h>1818+#include <linux/types.h>1919+#include <linux/kernel.h>2020+#include <linux/sched.h>2121+#include <linux/string.h>2222+#include <linux/ptrace.h>2323+#include <linux/errno.h>2424+#include <linux/ioport.h>2525+#include <linux/slab.h>2626+#include <linux/interrupt.h>2727+#include <linux/pci.h>2828+#include <linux/init.h>2929+#include <linux/delay.h>3030+#include <linux/netdevice.h>3131+#include <linux/etherdevice.h>3232+#include <linux/skbuff.h>3333+#include <linux/spinlock.h>3434+#include <linux/mii.h>3535+#include <linux/ethtool.h>3636+#include <linux/bitops.h>3737+3838+#include <asm/pgtable.h>3939+#include <asm/irq.h>4040+#include <asm/uaccess.h>4141+4242+#include "fs_enet.h"4343+4444+#ifdef CONFIG_8xx4545+static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)4646+{4747+ immap_t *im = (immap_t *)fs_enet_immap;4848+ void *dir, *dat, *ppar;4949+ int adv;5050+ u8 msk;5151+5252+ switch (port) {5353+ case fsiop_porta:5454+ dir = &im->im_ioport.iop_padir;5555+ dat = &im->im_ioport.iop_padat;5656+ ppar = &im->im_ioport.iop_papar;5757+ break;5858+5959+ case fsiop_portb:6060+ dir = &im->im_cpm.cp_pbdir;6161+ dat = &im->im_cpm.cp_pbdat;6262+ ppar = &im->im_cpm.cp_pbpar;6363+ break;6464+6565+ case fsiop_portc:6666+ dir = &im->im_ioport.iop_pcdir;6767+ dat = &im->im_ioport.iop_pcdat;6868+ ppar = &im->im_ioport.iop_pcpar;6969+ break;7070+7171+ case fsiop_portd:7272+ dir = &im->im_ioport.iop_pddir;7373+ dat = &im->im_ioport.iop_pddat;7474+ ppar = &im->im_ioport.iop_pdpar;7575+ break;7676+7777+ case fsiop_porte:7878+ dir = &im->im_cpm.cp_pedir;7979+ dat = &im->im_cpm.cp_pedat;8080+ ppar = &im->im_cpm.cp_pepar;8181+ break;8282+8383+ default:8484+ printk(KERN_ERR DRV_MODULE_NAME8585+ "Illegal port value %d!\n", port);8686+ return -EINVAL;8787+ }8888+8989+ adv = bit >> 3;9090+ dir = (char *)dir + adv;9191+ dat = (char *)dat + adv;9292+ ppar = (char *)ppar + adv;9393+9494+ msk = 1 << (7 - (bit & 7));9595+ if ((in_8(ppar) & msk) != 0) {9696+ printk(KERN_ERR DRV_MODULE_NAME9797+ "pin %d on port %d is not general purpose!\n", bit, port);9898+ return -EINVAL;9999+ }100100+101101+ *dirp = dir;102102+ *datp = dat;103103+ *mskp = msk;104104+105105+ return 0;106106+}107107+#endif108108+109109+#ifdef CONFIG_8260110110+static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)111111+{112112+ iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport;113113+ void *dir, *dat, *ppar;114114+ int adv;115115+ u8 msk;116116+117117+ switch (port) {118118+ case fsiop_porta:119119+ dir = &io->iop_pdira;120120+ dat = &io->iop_pdata;121121+ ppar = &io->iop_ppara;122122+ break;123123+124124+ case fsiop_portb:125125+ dir = &io->iop_pdirb;126126+ dat = &io->iop_pdatb;127127+ ppar = &io->iop_pparb;128128+ break;129129+130130+ case fsiop_portc:131131+ dir = &io->iop_pdirc;132132+ dat = &io->iop_pdatc;133133+ ppar = &io->iop_pparc;134134+ break;135135+136136+ case fsiop_portd:137137+ dir = &io->iop_pdird;138138+ dat = &io->iop_pdatd;139139+ ppar = &io->iop_ppard;140140+ break;141141+142142+ default:143143+ printk(KERN_ERR DRV_MODULE_NAME144144+ "Illegal port value %d!\n", port);145145+ return -EINVAL;146146+ }147147+148148+ adv = bit >> 3;149149+ dir = (char *)dir + adv;150150+ dat = (char *)dat + adv;151151+ ppar = (char *)ppar + adv;152152+153153+ msk = 1 << (7 - (bit & 7));154154+ if ((in_8(ppar) & msk) != 0) {155155+ printk(KERN_ERR DRV_MODULE_NAME156156+ "pin %d on port %d is not general purpose!\n", bit, port);157157+ return -EINVAL;158158+ }159159+160160+ *dirp = dir;161161+ *datp = dat;162162+ *mskp = msk;163163+164164+ return 0;165165+}166166+#endif167167+168168+static inline void bb_set(u8 *p, u8 m)169169+{170170+ out_8(p, in_8(p) | m);171171+}172172+173173+static inline void bb_clr(u8 *p, u8 m)174174+{175175+ out_8(p, in_8(p) & ~m);176176+}177177+178178+static inline int bb_read(u8 *p, u8 m)179179+{180180+ return (in_8(p) & m) != 0;181181+}182182+183183+static inline void mdio_active(struct fs_enet_mii_bus *bus)184184+{185185+ bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);186186+}187187+188188+static inline void mdio_tristate(struct fs_enet_mii_bus *bus)189189+{190190+ bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);191191+}192192+193193+static inline int mdio_read(struct fs_enet_mii_bus *bus)194194+{195195+ return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);196196+}197197+198198+static inline void mdio(struct fs_enet_mii_bus *bus, int what)199199+{200200+ if (what)201201+ bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);202202+ else203203+ bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);204204+}205205+206206+static inline void mdc(struct fs_enet_mii_bus *bus, int what)207207+{208208+ if (what)209209+ bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);210210+ else211211+ bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);212212+}213213+214214+static inline void mii_delay(struct fs_enet_mii_bus *bus)215215+{216216+ udelay(bus->bus_info->i.bitbang.delay);217217+}218218+219219+/* Utility to send the preamble, address, and register (common to read and write). */220220+static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg)221221+{222222+ int j;223223+224224+ /*225225+ * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.226226+ * The IEEE spec says this is a PHY optional requirement. The AMD227227+ * 79C874 requires one after power up and one after a MII communications228228+ * error. This means that we are doing more preambles than we need,229229+ * but it is safer and will be much more robust.230230+ */231231+232232+ mdio_active(bus);233233+ mdio(bus, 1);234234+ for (j = 0; j < 32; j++) {235235+ mdc(bus, 0);236236+ mii_delay(bus);237237+ mdc(bus, 1);238238+ mii_delay(bus);239239+ }240240+241241+ /* send the start bit (01) and the read opcode (10) or write (10) */242242+ mdc(bus, 0);243243+ mdio(bus, 0);244244+ mii_delay(bus);245245+ mdc(bus, 1);246246+ mii_delay(bus);247247+ mdc(bus, 0);248248+ mdio(bus, 1);249249+ mii_delay(bus);250250+ mdc(bus, 1);251251+ mii_delay(bus);252252+ mdc(bus, 0);253253+ mdio(bus, read);254254+ mii_delay(bus);255255+ mdc(bus, 1);256256+ mii_delay(bus);257257+ mdc(bus, 0);258258+ mdio(bus, !read);259259+ mii_delay(bus);260260+ mdc(bus, 1);261261+ mii_delay(bus);262262+263263+ /* send the PHY address */264264+ for (j = 0; j < 5; j++) {265265+ mdc(bus, 0);266266+ mdio(bus, (addr & 0x10) != 0);267267+ mii_delay(bus);268268+ mdc(bus, 1);269269+ mii_delay(bus);270270+ addr <<= 1;271271+ }272272+273273+ /* send the register address */274274+ for (j = 0; j < 5; j++) {275275+ mdc(bus, 0);276276+ mdio(bus, (reg & 0x10) != 0);277277+ mii_delay(bus);278278+ mdc(bus, 1);279279+ mii_delay(bus);280280+ reg <<= 1;281281+ }282282+}283283+284284+static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)285285+{286286+ u16 rdreg;287287+ int ret, j;288288+ u8 addr = phy_id & 0xff;289289+ u8 reg = location & 0xff;290290+291291+ bitbang_pre(bus, 1, addr, reg);292292+293293+ /* tri-state our MDIO I/O pin so we can read */294294+ mdc(bus, 0);295295+ mdio_tristate(bus);296296+ mii_delay(bus);297297+ mdc(bus, 1);298298+ mii_delay(bus);299299+300300+ /* check the turnaround bit: the PHY should be driving it to zero */301301+ if (mdio_read(bus) != 0) {302302+ /* PHY didn't drive TA low */303303+ for (j = 0; j < 32; j++) {304304+ mdc(bus, 0);305305+ mii_delay(bus);306306+ mdc(bus, 1);307307+ mii_delay(bus);308308+ }309309+ ret = -1;310310+ goto out;311311+ }312312+313313+ mdc(bus, 0);314314+ mii_delay(bus);315315+316316+ /* read 16 bits of register data, MSB first */317317+ rdreg = 0;318318+ for (j = 0; j < 16; j++) {319319+ mdc(bus, 1);320320+ mii_delay(bus);321321+ rdreg <<= 1;322322+ rdreg |= mdio_read(bus);323323+ mdc(bus, 0);324324+ mii_delay(bus);325325+ }326326+327327+ mdc(bus, 1);328328+ mii_delay(bus);329329+ mdc(bus, 0);330330+ mii_delay(bus);331331+ mdc(bus, 1);332332+ mii_delay(bus);333333+334334+ ret = rdreg;335335+out:336336+ return ret;337337+}338338+339339+static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)340340+{341341+ int j;342342+ u8 addr = phy_id & 0xff;343343+ u8 reg = location & 0xff;344344+ u16 value = val & 0xffff;345345+346346+ bitbang_pre(bus, 0, addr, reg);347347+348348+ /* send the turnaround (10) */349349+ mdc(bus, 0);350350+ mdio(bus, 1);351351+ mii_delay(bus);352352+ mdc(bus, 1);353353+ mii_delay(bus);354354+ mdc(bus, 0);355355+ mdio(bus, 0);356356+ mii_delay(bus);357357+ mdc(bus, 1);358358+ mii_delay(bus);359359+360360+ /* write 16 bits of register data, MSB first */361361+ for (j = 0; j < 16; j++) {362362+ mdc(bus, 0);363363+ mdio(bus, (value & 0x8000) != 0);364364+ mii_delay(bus);365365+ mdc(bus, 1);366366+ mii_delay(bus);367367+ value <<= 1;368368+ }369369+370370+ /*371371+ * Tri-state the MDIO line.372372+ */373373+ mdio_tristate(bus);374374+ mdc(bus, 0);375375+ mii_delay(bus);376376+ mdc(bus, 1);377377+ mii_delay(bus);378378+}379379+380380+int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus)381381+{382382+ const struct fs_mii_bus_info *bi = bus->bus_info;383383+ int r;384384+385385+ r = bitbang_prep_bit(&bus->bitbang.mdio_dir,386386+ &bus->bitbang.mdio_dat,387387+ &bus->bitbang.mdio_msk,388388+ bi->i.bitbang.mdio_port,389389+ bi->i.bitbang.mdio_bit);390390+ if (r != 0)391391+ return r;392392+393393+ r = bitbang_prep_bit(&bus->bitbang.mdc_dir,394394+ &bus->bitbang.mdc_dat,395395+ &bus->bitbang.mdc_msk,396396+ bi->i.bitbang.mdc_port,397397+ bi->i.bitbang.mdc_bit);398398+ if (r != 0)399399+ return r;400400+401401+ bus->mii_read = mii_read;402402+ bus->mii_write = mii_write;403403+404404+ return 0;405405+}
+92
drivers/net/fs_enet/mii-fixed.c
···11+/*22+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.33+ *44+ * Copyright (c) 2003 Intracom S.A. 55+ * by Pantelis Antoniou <panto@intracom.gr>66+ * 77+ * 2005 (c) MontaVista Software, Inc. 88+ * Vitaly Bordug <vbordug@ru.mvista.com>99+ *1010+ * This file is licensed under the terms of the GNU General Public License 1111+ * version 2. This program is licensed "as is" without any warranty of any 1212+ * kind, whether express or implied.1313+ */1414+1515+1616+#include <linux/config.h>1717+#include <linux/module.h>1818+#include <linux/types.h>1919+#include <linux/kernel.h>2020+#include <linux/sched.h>2121+#include <linux/string.h>2222+#include <linux/ptrace.h>2323+#include <linux/errno.h>2424+#include <linux/ioport.h>2525+#include <linux/slab.h>2626+#include <linux/interrupt.h>2727+#include <linux/pci.h>2828+#include <linux/init.h>2929+#include <linux/delay.h>3030+#include <linux/netdevice.h>3131+#include <linux/etherdevice.h>3232+#include <linux/skbuff.h>3333+#include <linux/spinlock.h>3434+#include <linux/mii.h>3535+#include <linux/ethtool.h>3636+#include <linux/bitops.h>3737+3838+#include <asm/pgtable.h>3939+#include <asm/irq.h>4040+#include <asm/uaccess.h>4141+4242+#include "fs_enet.h"4343+4444+static const u16 mii_regs[7] = {4545+ 0x3100,4646+ 0x786d,4747+ 0x0fff,4848+ 0x0fff,4949+ 0x01e1,5050+ 0x45e1,5151+ 0x0003,5252+};5353+5454+static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)5555+{5656+ int ret = 0;5757+5858+ if ((unsigned int)location >= ARRAY_SIZE(mii_regs))5959+ return -1;6060+6161+ if (location != 5)6262+ ret = mii_regs[location];6363+ else6464+ ret = bus->fixed.lpa;6565+6666+ return ret;6767+}6868+6969+static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)7070+{7171+ /* do nothing */7272+}7373+7474+int fs_mii_fixed_init(struct fs_enet_mii_bus *bus)7575+{7676+ const struct fs_mii_bus_info *bi = bus->bus_info;7777+7878+ bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */7979+8080+ /* if speed is fixed at 10Mb, remove 100Mb modes */8181+ if (bi->i.fixed.speed == 10)8282+ bus->fixed.lpa &= ~LPA_100;8383+8484+ /* if duplex is half, remove full duplex modes */8585+ if (bi->i.fixed.duplex == 0)8686+ bus->fixed.lpa &= ~LPA_DUPLEX;8787+8888+ bus->mii_read = mii_read;8989+ bus->mii_write = mii_write;9090+9191+ return 0;9292+}
+136
include/linux/fs_enet_pd.h
···11+/*22+ * Platform information definitions for the33+ * universal Freescale Ethernet driver.44+ *55+ * Copyright (c) 2003 Intracom S.A. 66+ * by Pantelis Antoniou <panto@intracom.gr>77+ *88+ * 2005 (c) MontaVista Software, Inc. 99+ * Vitaly Bordug <vbordug@ru.mvista.com>1010+ *1111+ * This file is licensed under the terms of the GNU General Public License 1212+ * version 2. This program is licensed "as is" without any warranty of any 1313+ * kind, whether express or implied.1414+ */1515+1616+#ifndef FS_ENET_PD_H1717+#define FS_ENET_PD_H1818+1919+#include <linux/version.h>2020+#include <asm/types.h>2121+2222+#define FS_ENET_NAME "fs_enet"2323+2424+enum fs_id {2525+ fsid_fec1,2626+ fsid_fec2,2727+ fsid_fcc1,2828+ fsid_fcc2,2929+ fsid_fcc3,3030+ fsid_scc1,3131+ fsid_scc2,3232+ fsid_scc3,3333+ fsid_scc4,3434+};3535+3636+#define FS_MAX_INDEX 93737+3838+static inline int fs_get_fec_index(enum fs_id id)3939+{4040+ if (id >= fsid_fec1 && id <= fsid_fec2)4141+ return id - fsid_fec1;4242+ return -1;4343+}4444+4545+static inline int fs_get_fcc_index(enum fs_id id)4646+{4747+ if (id >= fsid_fcc1 && id <= fsid_fcc3)4848+ return id - fsid_fcc1;4949+ return -1;5050+}5151+5252+static inline int fs_get_scc_index(enum fs_id id)5353+{5454+ if (id >= fsid_scc1 && id <= fsid_scc4)5555+ return id - fsid_scc1;5656+ return -1;5757+}5858+5959+enum fs_mii_method {6060+ fsmii_fixed,6161+ fsmii_fec,6262+ fsmii_bitbang,6363+};6464+6565+enum fs_ioport {6666+ fsiop_porta,6767+ fsiop_portb,6868+ fsiop_portc,6969+ fsiop_portd,7070+ fsiop_porte,7171+};7272+7373+struct fs_mii_bus_info {7474+ int method; /* mii method */7575+ int id; /* the id of the mii_bus */7676+ int disable_aneg; /* if the controller needs to negothiate speed & duplex */7777+ int lpa; /* the default board-specific vallues will be applied otherwise */7878+7979+ union {8080+ struct {8181+ int duplex;8282+ int speed;8383+ } fixed;8484+8585+ struct {8686+ /* nothing */8787+ } fec;8888+8989+ struct {9090+ /* nothing */9191+ } scc;9292+9393+ struct {9494+ int mdio_port; /* port & bit for MDIO */9595+ int mdio_bit;9696+ int mdc_port; /* port & bit for MDC */9797+ int mdc_bit;9898+ int delay; /* delay in us */9999+ } bitbang;100100+ } i;101101+};102102+103103+struct fs_platform_info {104104+105105+ void(*init_ioports)(void);106106+ /* device specific information */107107+ int fs_no; /* controller index */108108+109109+ u32 cp_page; /* CPM page */110110+ u32 cp_block; /* CPM sblock */111111+112112+ u32 clk_trx; /* some stuff for pins & mux configuration*/113113+ u32 clk_route;114114+ u32 clk_mask;115115+116116+ u32 mem_offset;117117+ u32 dpram_offset;118118+ u32 fcc_regs_c;119119+120120+ u32 device_flags;121121+122122+ int phy_addr; /* the phy address (-1 no phy) */123123+ int phy_irq; /* the phy irq (if it exists) */124124+125125+ const struct fs_mii_bus_info *bus_info;126126+127127+ int rx_ring, tx_ring; /* number of buffers on rx */128128+ __u8 macaddr[6]; /* mac address */129129+ int rx_copybreak; /* limit we copy small frames */130130+ int use_napi; /* use NAPI */131131+ int napi_weight; /* NAPI weight */132132+133133+ int use_rmii; /* use RMII mode */134134+};135135+136136+#endif