1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Driver for Gigabit Ethernet adapters based on the Session Layer
- * Interface (SLIC) technology by Alacritech. The driver does not
- * support the hardware acceleration features provided by these cards.
- *
- * Copyright (C) 2016 Lino Sanfilippo <[email protected]>
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/if_ether.h>
- #include <linux/crc32.h>
- #include <linux/dma-mapping.h>
- #include <linux/ethtool.h>
- #include <linux/mii.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/firmware.h>
- #include <linux/list.h>
- #include <linux/u64_stats_sync.h>
- #include "slic.h"
- #define DRV_NAME "slicoss"
- static const struct pci_device_id slic_id_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ALACRITECH,
- PCI_DEVICE_ID_ALACRITECH_MOJAVE) },
- { PCI_DEVICE(PCI_VENDOR_ID_ALACRITECH,
- PCI_DEVICE_ID_ALACRITECH_OASIS) },
- { 0 }
- };
- static const char slic_stats_strings[][ETH_GSTRING_LEN] = {
- "rx_packets",
- "rx_bytes",
- "rx_multicasts",
- "rx_errors",
- "rx_buff_miss",
- "rx_tp_csum",
- "rx_tp_oflow",
- "rx_tp_hlen",
- "rx_ip_csum",
- "rx_ip_len",
- "rx_ip_hdr_len",
- "rx_early",
- "rx_buff_oflow",
- "rx_lcode",
- "rx_drbl",
- "rx_crc",
- "rx_oflow_802",
- "rx_uflow_802",
- "tx_packets",
- "tx_bytes",
- "tx_carrier",
- "tx_dropped",
- "irq_errs",
- };
- static inline int slic_next_queue_idx(unsigned int idx, unsigned int qlen)
- {
- return (idx + 1) & (qlen - 1);
- }
- static inline int slic_get_free_queue_descs(unsigned int put_idx,
- unsigned int done_idx,
- unsigned int qlen)
- {
- if (put_idx >= done_idx)
- return (qlen - (put_idx - done_idx) - 1);
- return (done_idx - put_idx - 1);
- }
- static unsigned int slic_next_compl_idx(struct slic_device *sdev)
- {
- struct slic_stat_queue *stq = &sdev->stq;
- unsigned int active = stq->active_array;
- struct slic_stat_desc *descs;
- struct slic_stat_desc *stat;
- unsigned int idx;
- descs = stq->descs[active];
- stat = &descs[stq->done_idx];
- if (!stat->status)
- return SLIC_INVALID_STAT_DESC_IDX;
- idx = (le32_to_cpu(stat->hnd) & 0xffff) - 1;
- /* reset desc */
- stat->hnd = 0;
- stat->status = 0;
- stq->done_idx = slic_next_queue_idx(stq->done_idx, stq->len);
- /* check for wraparound */
- if (!stq->done_idx) {
- dma_addr_t paddr = stq->paddr[active];
- slic_write(sdev, SLIC_REG_RBAR, lower_32_bits(paddr) |
- stq->len);
- /* make sure new status descriptors are immediately available */
- slic_flush_write(sdev);
- active++;
- active &= (SLIC_NUM_STAT_DESC_ARRAYS - 1);
- stq->active_array = active;
- }
- return idx;
- }
- static unsigned int slic_get_free_tx_descs(struct slic_tx_queue *txq)
- {
- /* ensure tail idx is updated */
- smp_mb();
- return slic_get_free_queue_descs(txq->put_idx, txq->done_idx, txq->len);
- }
- static unsigned int slic_get_free_rx_descs(struct slic_rx_queue *rxq)
- {
- return slic_get_free_queue_descs(rxq->put_idx, rxq->done_idx, rxq->len);
- }
- static void slic_clear_upr_list(struct slic_upr_list *upr_list)
- {
- struct slic_upr *upr;
- struct slic_upr *tmp;
- spin_lock_bh(&upr_list->lock);
- list_for_each_entry_safe(upr, tmp, &upr_list->list, list) {
- list_del(&upr->list);
- kfree(upr);
- }
- upr_list->pending = false;
- spin_unlock_bh(&upr_list->lock);
- }
- static void slic_start_upr(struct slic_device *sdev, struct slic_upr *upr)
- {
- u32 reg;
- reg = (upr->type == SLIC_UPR_CONFIG) ? SLIC_REG_RCONFIG :
- SLIC_REG_LSTAT;
- slic_write(sdev, reg, lower_32_bits(upr->paddr));
- slic_flush_write(sdev);
- }
- static void slic_queue_upr(struct slic_device *sdev, struct slic_upr *upr)
- {
- struct slic_upr_list *upr_list = &sdev->upr_list;
- bool pending;
- spin_lock_bh(&upr_list->lock);
- pending = upr_list->pending;
- INIT_LIST_HEAD(&upr->list);
- list_add_tail(&upr->list, &upr_list->list);
- upr_list->pending = true;
- spin_unlock_bh(&upr_list->lock);
- if (!pending)
- slic_start_upr(sdev, upr);
- }
- static struct slic_upr *slic_dequeue_upr(struct slic_device *sdev)
- {
- struct slic_upr_list *upr_list = &sdev->upr_list;
- struct slic_upr *next_upr = NULL;
- struct slic_upr *upr = NULL;
- spin_lock_bh(&upr_list->lock);
- if (!list_empty(&upr_list->list)) {
- upr = list_first_entry(&upr_list->list, struct slic_upr, list);
- list_del(&upr->list);
- if (list_empty(&upr_list->list))
- upr_list->pending = false;
- else
- next_upr = list_first_entry(&upr_list->list,
- struct slic_upr, list);
- }
- spin_unlock_bh(&upr_list->lock);
- /* trigger processing of the next upr in list */
- if (next_upr)
- slic_start_upr(sdev, next_upr);
- return upr;
- }
- static int slic_new_upr(struct slic_device *sdev, unsigned int type,
- dma_addr_t paddr)
- {
- struct slic_upr *upr;
- upr = kmalloc(sizeof(*upr), GFP_ATOMIC);
- if (!upr)
- return -ENOMEM;
- upr->type = type;
- upr->paddr = paddr;
- slic_queue_upr(sdev, upr);
- return 0;
- }
- static void slic_set_mcast_bit(u64 *mcmask, unsigned char const *addr)
- {
- u64 mask = *mcmask;
- u8 crc;
- /* Get the CRC polynomial for the mac address: we use bits 1-8 (lsb),
- * bitwise reversed, msb (= lsb bit 0 before bitrev) is automatically
- * discarded.
- */
- crc = ether_crc(ETH_ALEN, addr) >> 23;
- /* we only have space on the SLIC for 64 entries */
- crc &= 0x3F;
- mask |= (u64)1 << crc;
- *mcmask = mask;
- }
- /* must be called with link_lock held */
- static void slic_configure_rcv(struct slic_device *sdev)
- {
- u32 val;
- val = SLIC_GRCR_RESET | SLIC_GRCR_ADDRAEN | SLIC_GRCR_RCVEN |
- SLIC_GRCR_HASHSIZE << SLIC_GRCR_HASHSIZE_SHIFT | SLIC_GRCR_RCVBAD;
- if (sdev->duplex == DUPLEX_FULL)
- val |= SLIC_GRCR_CTLEN;
- if (sdev->promisc)
- val |= SLIC_GRCR_RCVALL;
- slic_write(sdev, SLIC_REG_WRCFG, val);
- }
- /* must be called with link_lock held */
- static void slic_configure_xmt(struct slic_device *sdev)
- {
- u32 val;
- val = SLIC_GXCR_RESET | SLIC_GXCR_XMTEN;
- if (sdev->duplex == DUPLEX_FULL)
- val |= SLIC_GXCR_PAUSEEN;
- slic_write(sdev, SLIC_REG_WXCFG, val);
- }
- /* must be called with link_lock held */
- static void slic_configure_mac(struct slic_device *sdev)
- {
- u32 val;
- if (sdev->speed == SPEED_1000) {
- val = SLIC_GMCR_GAPBB_1000 << SLIC_GMCR_GAPBB_SHIFT |
- SLIC_GMCR_GAPR1_1000 << SLIC_GMCR_GAPR1_SHIFT |
- SLIC_GMCR_GAPR2_1000 << SLIC_GMCR_GAPR2_SHIFT |
- SLIC_GMCR_GBIT; /* enable GMII */
- } else {
- val = SLIC_GMCR_GAPBB_100 << SLIC_GMCR_GAPBB_SHIFT |
- SLIC_GMCR_GAPR1_100 << SLIC_GMCR_GAPR1_SHIFT |
- SLIC_GMCR_GAPR2_100 << SLIC_GMCR_GAPR2_SHIFT;
- }
- if (sdev->duplex == DUPLEX_FULL)
- val |= SLIC_GMCR_FULLD;
- slic_write(sdev, SLIC_REG_WMCFG, val);
- }
- static void slic_configure_link_locked(struct slic_device *sdev, int speed,
- unsigned int duplex)
- {
- struct net_device *dev = sdev->netdev;
- if (sdev->speed == speed && sdev->duplex == duplex)
- return;
- sdev->speed = speed;
- sdev->duplex = duplex;
- if (sdev->speed == SPEED_UNKNOWN) {
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
- } else {
- /* (re)configure link settings */
- slic_configure_mac(sdev);
- slic_configure_xmt(sdev);
- slic_configure_rcv(sdev);
- slic_flush_write(sdev);
- if (!netif_carrier_ok(dev))
- netif_carrier_on(dev);
- }
- }
- static void slic_configure_link(struct slic_device *sdev, int speed,
- unsigned int duplex)
- {
- spin_lock_bh(&sdev->link_lock);
- slic_configure_link_locked(sdev, speed, duplex);
- spin_unlock_bh(&sdev->link_lock);
- }
- static void slic_set_rx_mode(struct net_device *dev)
- {
- struct slic_device *sdev = netdev_priv(dev);
- struct netdev_hw_addr *hwaddr;
- bool set_promisc;
- u64 mcmask;
- if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
- /* Turn on all multicast addresses. We have to do this for
- * promiscuous mode as well as ALLMCAST mode (it saves the
- * microcode from having to keep state about the MAC
- * configuration).
- */
- mcmask = ~(u64)0;
- } else {
- mcmask = 0;
- netdev_for_each_mc_addr(hwaddr, dev) {
- slic_set_mcast_bit(&mcmask, hwaddr->addr);
- }
- }
- slic_write(sdev, SLIC_REG_MCASTLOW, lower_32_bits(mcmask));
- slic_write(sdev, SLIC_REG_MCASTHIGH, upper_32_bits(mcmask));
- set_promisc = !!(dev->flags & IFF_PROMISC);
- spin_lock_bh(&sdev->link_lock);
- if (sdev->promisc != set_promisc) {
- sdev->promisc = set_promisc;
- slic_configure_rcv(sdev);
- }
- spin_unlock_bh(&sdev->link_lock);
- }
- static void slic_xmit_complete(struct slic_device *sdev)
- {
- struct slic_tx_queue *txq = &sdev->txq;
- struct net_device *dev = sdev->netdev;
- struct slic_tx_buffer *buff;
- unsigned int frames = 0;
- unsigned int bytes = 0;
- unsigned int idx;
- /* Limit processing to SLIC_MAX_TX_COMPLETIONS frames to avoid that new
- * completions during processing keeps the loop running endlessly.
- */
- do {
- idx = slic_next_compl_idx(sdev);
- if (idx == SLIC_INVALID_STAT_DESC_IDX)
- break;
- txq->done_idx = idx;
- buff = &txq->txbuffs[idx];
- if (unlikely(!buff->skb)) {
- netdev_warn(dev,
- "no skb found for desc idx %i\n", idx);
- continue;
- }
- dma_unmap_single(&sdev->pdev->dev,
- dma_unmap_addr(buff, map_addr),
- dma_unmap_len(buff, map_len), DMA_TO_DEVICE);
- bytes += buff->skb->len;
- frames++;
- dev_kfree_skb_any(buff->skb);
- buff->skb = NULL;
- } while (frames < SLIC_MAX_TX_COMPLETIONS);
- /* make sure xmit sees the new value for done_idx */
- smp_wmb();
- u64_stats_update_begin(&sdev->stats.syncp);
- sdev->stats.tx_bytes += bytes;
- sdev->stats.tx_packets += frames;
- u64_stats_update_end(&sdev->stats.syncp);
- netif_tx_lock(dev);
- if (netif_queue_stopped(dev) &&
- (slic_get_free_tx_descs(txq) >= SLIC_MIN_TX_WAKEUP_DESCS))
- netif_wake_queue(dev);
- netif_tx_unlock(dev);
- }
- static void slic_refill_rx_queue(struct slic_device *sdev, gfp_t gfp)
- {
- const unsigned int ALIGN_MASK = SLIC_RX_BUFF_ALIGN - 1;
- unsigned int maplen = SLIC_RX_BUFF_SIZE;
- struct slic_rx_queue *rxq = &sdev->rxq;
- struct net_device *dev = sdev->netdev;
- struct slic_rx_buffer *buff;
- struct slic_rx_desc *desc;
- unsigned int misalign;
- unsigned int offset;
- struct sk_buff *skb;
- dma_addr_t paddr;
- while (slic_get_free_rx_descs(rxq) > SLIC_MAX_REQ_RX_DESCS) {
- skb = alloc_skb(maplen + ALIGN_MASK, gfp);
- if (!skb)
- break;
- paddr = dma_map_single(&sdev->pdev->dev, skb->data, maplen,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&sdev->pdev->dev, paddr)) {
- netdev_err(dev, "mapping rx packet failed\n");
- /* drop skb */
- dev_kfree_skb_any(skb);
- break;
- }
- /* ensure head buffer descriptors are 256 byte aligned */
- offset = 0;
- misalign = paddr & ALIGN_MASK;
- if (misalign) {
- offset = SLIC_RX_BUFF_ALIGN - misalign;
- skb_reserve(skb, offset);
- }
- /* the HW expects dma chunks for descriptor + frame data */
- desc = (struct slic_rx_desc *)skb->data;
- /* temporarily sync descriptor for CPU to clear status */
- dma_sync_single_for_cpu(&sdev->pdev->dev, paddr,
- offset + sizeof(*desc),
- DMA_FROM_DEVICE);
- desc->status = 0;
- /* return it to HW again */
- dma_sync_single_for_device(&sdev->pdev->dev, paddr,
- offset + sizeof(*desc),
- DMA_FROM_DEVICE);
- buff = &rxq->rxbuffs[rxq->put_idx];
- buff->skb = skb;
- dma_unmap_addr_set(buff, map_addr, paddr);
- dma_unmap_len_set(buff, map_len, maplen);
- buff->addr_offset = offset;
- /* complete write to descriptor before it is handed to HW */
- wmb();
- /* head buffer descriptors are placed immediately before skb */
- slic_write(sdev, SLIC_REG_HBAR, lower_32_bits(paddr) + offset);
- rxq->put_idx = slic_next_queue_idx(rxq->put_idx, rxq->len);
- }
- }
- static void slic_handle_frame_error(struct slic_device *sdev,
- struct sk_buff *skb)
- {
- struct slic_stats *stats = &sdev->stats;
- if (sdev->model == SLIC_MODEL_OASIS) {
- struct slic_rx_info_oasis *info;
- u32 status_b;
- u32 status;
- info = (struct slic_rx_info_oasis *)skb->data;
- status = le32_to_cpu(info->frame_status);
- status_b = le32_to_cpu(info->frame_status_b);
- /* transport layer */
- if (status_b & SLIC_VRHSTATB_TPCSUM)
- SLIC_INC_STATS_COUNTER(stats, rx_tpcsum);
- if (status & SLIC_VRHSTAT_TPOFLO)
- SLIC_INC_STATS_COUNTER(stats, rx_tpoflow);
- if (status_b & SLIC_VRHSTATB_TPHLEN)
- SLIC_INC_STATS_COUNTER(stats, rx_tphlen);
- /* ip layer */
- if (status_b & SLIC_VRHSTATB_IPCSUM)
- SLIC_INC_STATS_COUNTER(stats, rx_ipcsum);
- if (status_b & SLIC_VRHSTATB_IPLERR)
- SLIC_INC_STATS_COUNTER(stats, rx_iplen);
- if (status_b & SLIC_VRHSTATB_IPHERR)
- SLIC_INC_STATS_COUNTER(stats, rx_iphlen);
- /* link layer */
- if (status_b & SLIC_VRHSTATB_RCVE)
- SLIC_INC_STATS_COUNTER(stats, rx_early);
- if (status_b & SLIC_VRHSTATB_BUFF)
- SLIC_INC_STATS_COUNTER(stats, rx_buffoflow);
- if (status_b & SLIC_VRHSTATB_CODE)
- SLIC_INC_STATS_COUNTER(stats, rx_lcode);
- if (status_b & SLIC_VRHSTATB_DRBL)
- SLIC_INC_STATS_COUNTER(stats, rx_drbl);
- if (status_b & SLIC_VRHSTATB_CRC)
- SLIC_INC_STATS_COUNTER(stats, rx_crc);
- if (status & SLIC_VRHSTAT_802OE)
- SLIC_INC_STATS_COUNTER(stats, rx_oflow802);
- if (status_b & SLIC_VRHSTATB_802UE)
- SLIC_INC_STATS_COUNTER(stats, rx_uflow802);
- if (status_b & SLIC_VRHSTATB_CARRE)
- SLIC_INC_STATS_COUNTER(stats, tx_carrier);
- } else { /* mojave */
- struct slic_rx_info_mojave *info;
- u32 status;
- info = (struct slic_rx_info_mojave *)skb->data;
- status = le32_to_cpu(info->frame_status);
- /* transport layer */
- if (status & SLIC_VGBSTAT_XPERR) {
- u32 xerr = status >> SLIC_VGBSTAT_XERRSHFT;
- if (xerr == SLIC_VGBSTAT_XCSERR)
- SLIC_INC_STATS_COUNTER(stats, rx_tpcsum);
- if (xerr == SLIC_VGBSTAT_XUFLOW)
- SLIC_INC_STATS_COUNTER(stats, rx_tpoflow);
- if (xerr == SLIC_VGBSTAT_XHLEN)
- SLIC_INC_STATS_COUNTER(stats, rx_tphlen);
- }
- /* ip layer */
- if (status & SLIC_VGBSTAT_NETERR) {
- u32 nerr = status >> SLIC_VGBSTAT_NERRSHFT &
- SLIC_VGBSTAT_NERRMSK;
- if (nerr == SLIC_VGBSTAT_NCSERR)
- SLIC_INC_STATS_COUNTER(stats, rx_ipcsum);
- if (nerr == SLIC_VGBSTAT_NUFLOW)
- SLIC_INC_STATS_COUNTER(stats, rx_iplen);
- if (nerr == SLIC_VGBSTAT_NHLEN)
- SLIC_INC_STATS_COUNTER(stats, rx_iphlen);
- }
- /* link layer */
- if (status & SLIC_VGBSTAT_LNKERR) {
- u32 lerr = status & SLIC_VGBSTAT_LERRMSK;
- if (lerr == SLIC_VGBSTAT_LDEARLY)
- SLIC_INC_STATS_COUNTER(stats, rx_early);
- if (lerr == SLIC_VGBSTAT_LBOFLO)
- SLIC_INC_STATS_COUNTER(stats, rx_buffoflow);
- if (lerr == SLIC_VGBSTAT_LCODERR)
- SLIC_INC_STATS_COUNTER(stats, rx_lcode);
- if (lerr == SLIC_VGBSTAT_LDBLNBL)
- SLIC_INC_STATS_COUNTER(stats, rx_drbl);
- if (lerr == SLIC_VGBSTAT_LCRCERR)
- SLIC_INC_STATS_COUNTER(stats, rx_crc);
- if (lerr == SLIC_VGBSTAT_LOFLO)
- SLIC_INC_STATS_COUNTER(stats, rx_oflow802);
- if (lerr == SLIC_VGBSTAT_LUFLO)
- SLIC_INC_STATS_COUNTER(stats, rx_uflow802);
- }
- }
- SLIC_INC_STATS_COUNTER(stats, rx_errors);
- }
- static void slic_handle_receive(struct slic_device *sdev, unsigned int todo,
- unsigned int *done)
- {
- struct slic_rx_queue *rxq = &sdev->rxq;
- struct net_device *dev = sdev->netdev;
- struct slic_rx_buffer *buff;
- struct slic_rx_desc *desc;
- unsigned int frames = 0;
- unsigned int bytes = 0;
- struct sk_buff *skb;
- u32 status;
- u32 len;
- while (todo && (rxq->done_idx != rxq->put_idx)) {
- buff = &rxq->rxbuffs[rxq->done_idx];
- skb = buff->skb;
- if (!skb)
- break;
- desc = (struct slic_rx_desc *)skb->data;
- dma_sync_single_for_cpu(&sdev->pdev->dev,
- dma_unmap_addr(buff, map_addr),
- buff->addr_offset + sizeof(*desc),
- DMA_FROM_DEVICE);
- status = le32_to_cpu(desc->status);
- if (!(status & SLIC_IRHDDR_SVALID)) {
- dma_sync_single_for_device(&sdev->pdev->dev,
- dma_unmap_addr(buff,
- map_addr),
- buff->addr_offset +
- sizeof(*desc),
- DMA_FROM_DEVICE);
- break;
- }
- buff->skb = NULL;
- dma_unmap_single(&sdev->pdev->dev,
- dma_unmap_addr(buff, map_addr),
- dma_unmap_len(buff, map_len),
- DMA_FROM_DEVICE);
- /* skip rx descriptor that is placed before the frame data */
- skb_reserve(skb, SLIC_RX_BUFF_HDR_SIZE);
- if (unlikely(status & SLIC_IRHDDR_ERR)) {
- slic_handle_frame_error(sdev, skb);
- dev_kfree_skb_any(skb);
- } else {
- struct ethhdr *eh = (struct ethhdr *)skb->data;
- if (is_multicast_ether_addr(eh->h_dest))
- SLIC_INC_STATS_COUNTER(&sdev->stats, rx_mcasts);
- len = le32_to_cpu(desc->length) & SLIC_IRHDDR_FLEN_MSK;
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- napi_gro_receive(&sdev->napi, skb);
- bytes += len;
- frames++;
- }
- rxq->done_idx = slic_next_queue_idx(rxq->done_idx, rxq->len);
- todo--;
- }
- u64_stats_update_begin(&sdev->stats.syncp);
- sdev->stats.rx_bytes += bytes;
- sdev->stats.rx_packets += frames;
- u64_stats_update_end(&sdev->stats.syncp);
- slic_refill_rx_queue(sdev, GFP_ATOMIC);
- }
- static void slic_handle_link_irq(struct slic_device *sdev)
- {
- struct slic_shmem *sm = &sdev->shmem;
- struct slic_shmem_data *sm_data = sm->shmem_data;
- unsigned int duplex;
- int speed;
- u32 link;
- link = le32_to_cpu(sm_data->link);
- if (link & SLIC_GIG_LINKUP) {
- if (link & SLIC_GIG_SPEED_1000)
- speed = SPEED_1000;
- else if (link & SLIC_GIG_SPEED_100)
- speed = SPEED_100;
- else
- speed = SPEED_10;
- duplex = (link & SLIC_GIG_FULLDUPLEX) ? DUPLEX_FULL :
- DUPLEX_HALF;
- } else {
- duplex = DUPLEX_UNKNOWN;
- speed = SPEED_UNKNOWN;
- }
- slic_configure_link(sdev, speed, duplex);
- }
- static void slic_handle_upr_irq(struct slic_device *sdev, u32 irqs)
- {
- struct slic_upr *upr;
- /* remove upr that caused this irq (always the first entry in list) */
- upr = slic_dequeue_upr(sdev);
- if (!upr) {
- netdev_warn(sdev->netdev, "no upr found on list\n");
- return;
- }
- if (upr->type == SLIC_UPR_LSTAT) {
- if (unlikely(irqs & SLIC_ISR_UPCERR_MASK)) {
- /* try again */
- slic_queue_upr(sdev, upr);
- return;
- }
- slic_handle_link_irq(sdev);
- }
- kfree(upr);
- }
- static int slic_handle_link_change(struct slic_device *sdev)
- {
- return slic_new_upr(sdev, SLIC_UPR_LSTAT, sdev->shmem.link_paddr);
- }
- static void slic_handle_err_irq(struct slic_device *sdev, u32 isr)
- {
- struct slic_stats *stats = &sdev->stats;
- if (isr & SLIC_ISR_RMISS)
- SLIC_INC_STATS_COUNTER(stats, rx_buff_miss);
- if (isr & SLIC_ISR_XDROP)
- SLIC_INC_STATS_COUNTER(stats, tx_dropped);
- if (!(isr & (SLIC_ISR_RMISS | SLIC_ISR_XDROP)))
- SLIC_INC_STATS_COUNTER(stats, irq_errs);
- }
- static void slic_handle_irq(struct slic_device *sdev, u32 isr,
- unsigned int todo, unsigned int *done)
- {
- if (isr & SLIC_ISR_ERR)
- slic_handle_err_irq(sdev, isr);
- if (isr & SLIC_ISR_LEVENT)
- slic_handle_link_change(sdev);
- if (isr & SLIC_ISR_UPC_MASK)
- slic_handle_upr_irq(sdev, isr);
- if (isr & SLIC_ISR_RCV)
- slic_handle_receive(sdev, todo, done);
- if (isr & SLIC_ISR_CMD)
- slic_xmit_complete(sdev);
- }
- static int slic_poll(struct napi_struct *napi, int todo)
- {
- struct slic_device *sdev = container_of(napi, struct slic_device, napi);
- struct slic_shmem *sm = &sdev->shmem;
- struct slic_shmem_data *sm_data = sm->shmem_data;
- u32 isr = le32_to_cpu(sm_data->isr);
- int done = 0;
- slic_handle_irq(sdev, isr, todo, &done);
- if (done < todo) {
- napi_complete_done(napi, done);
- /* reenable irqs */
- sm_data->isr = 0;
- /* make sure sm_data->isr is cleard before irqs are reenabled */
- wmb();
- slic_write(sdev, SLIC_REG_ISR, 0);
- slic_flush_write(sdev);
- }
- return done;
- }
- static irqreturn_t slic_irq(int irq, void *dev_id)
- {
- struct slic_device *sdev = dev_id;
- struct slic_shmem *sm = &sdev->shmem;
- struct slic_shmem_data *sm_data = sm->shmem_data;
- slic_write(sdev, SLIC_REG_ICR, SLIC_ICR_INT_MASK);
- slic_flush_write(sdev);
- /* make sure sm_data->isr is read after ICR_INT_MASK is set */
- wmb();
- if (!sm_data->isr) {
- dma_rmb();
- /* spurious interrupt */
- slic_write(sdev, SLIC_REG_ISR, 0);
- slic_flush_write(sdev);
- return IRQ_NONE;
- }
- napi_schedule_irqoff(&sdev->napi);
- return IRQ_HANDLED;
- }
- static void slic_card_reset(struct slic_device *sdev)
- {
- u16 cmd;
- slic_write(sdev, SLIC_REG_RESET, SLIC_RESET_MAGIC);
- /* flush write by means of config space */
- pci_read_config_word(sdev->pdev, PCI_COMMAND, &cmd);
- mdelay(1);
- }
- static int slic_init_stat_queue(struct slic_device *sdev)
- {
- const unsigned int DESC_ALIGN_MASK = SLIC_STATS_DESC_ALIGN - 1;
- struct slic_stat_queue *stq = &sdev->stq;
- struct slic_stat_desc *descs;
- unsigned int misalign;
- unsigned int offset;
- dma_addr_t paddr;
- size_t size;
- int err;
- int i;
- stq->len = SLIC_NUM_STAT_DESCS;
- stq->active_array = 0;
- stq->done_idx = 0;
- size = stq->len * sizeof(*descs) + DESC_ALIGN_MASK;
- for (i = 0; i < SLIC_NUM_STAT_DESC_ARRAYS; i++) {
- descs = dma_alloc_coherent(&sdev->pdev->dev, size, &paddr,
- GFP_KERNEL);
- if (!descs) {
- netdev_err(sdev->netdev,
- "failed to allocate status descriptors\n");
- err = -ENOMEM;
- goto free_descs;
- }
- /* ensure correct alignment */
- offset = 0;
- misalign = paddr & DESC_ALIGN_MASK;
- if (misalign) {
- offset = SLIC_STATS_DESC_ALIGN - misalign;
- descs += offset;
- paddr += offset;
- }
- slic_write(sdev, SLIC_REG_RBAR, lower_32_bits(paddr) |
- stq->len);
- stq->descs[i] = descs;
- stq->paddr[i] = paddr;
- stq->addr_offset[i] = offset;
- }
- stq->mem_size = size;
- return 0;
- free_descs:
- while (i--) {
- dma_free_coherent(&sdev->pdev->dev, stq->mem_size,
- stq->descs[i] - stq->addr_offset[i],
- stq->paddr[i] - stq->addr_offset[i]);
- }
- return err;
- }
- static void slic_free_stat_queue(struct slic_device *sdev)
- {
- struct slic_stat_queue *stq = &sdev->stq;
- int i;
- for (i = 0; i < SLIC_NUM_STAT_DESC_ARRAYS; i++) {
- dma_free_coherent(&sdev->pdev->dev, stq->mem_size,
- stq->descs[i] - stq->addr_offset[i],
- stq->paddr[i] - stq->addr_offset[i]);
- }
- }
- static int slic_init_tx_queue(struct slic_device *sdev)
- {
- struct slic_tx_queue *txq = &sdev->txq;
- struct slic_tx_buffer *buff;
- struct slic_tx_desc *desc;
- unsigned int i;
- int err;
- txq->len = SLIC_NUM_TX_DESCS;
- txq->put_idx = 0;
- txq->done_idx = 0;
- txq->txbuffs = kcalloc(txq->len, sizeof(*buff), GFP_KERNEL);
- if (!txq->txbuffs)
- return -ENOMEM;
- txq->dma_pool = dma_pool_create("slic_pool", &sdev->pdev->dev,
- sizeof(*desc), SLIC_TX_DESC_ALIGN,
- 4096);
- if (!txq->dma_pool) {
- err = -ENOMEM;
- netdev_err(sdev->netdev, "failed to create dma pool\n");
- goto free_buffs;
- }
- for (i = 0; i < txq->len; i++) {
- buff = &txq->txbuffs[i];
- desc = dma_pool_zalloc(txq->dma_pool, GFP_KERNEL,
- &buff->desc_paddr);
- if (!desc) {
- netdev_err(sdev->netdev,
- "failed to alloc pool chunk (%i)\n", i);
- err = -ENOMEM;
- goto free_descs;
- }
- desc->hnd = cpu_to_le32((u32)(i + 1));
- desc->cmd = SLIC_CMD_XMT_REQ;
- desc->flags = 0;
- desc->type = cpu_to_le32(SLIC_CMD_TYPE_DUMB);
- buff->desc = desc;
- }
- return 0;
- free_descs:
- while (i--) {
- buff = &txq->txbuffs[i];
- dma_pool_free(txq->dma_pool, buff->desc, buff->desc_paddr);
- }
- dma_pool_destroy(txq->dma_pool);
- free_buffs:
- kfree(txq->txbuffs);
- return err;
- }
- static void slic_free_tx_queue(struct slic_device *sdev)
- {
- struct slic_tx_queue *txq = &sdev->txq;
- struct slic_tx_buffer *buff;
- unsigned int i;
- for (i = 0; i < txq->len; i++) {
- buff = &txq->txbuffs[i];
- dma_pool_free(txq->dma_pool, buff->desc, buff->desc_paddr);
- if (!buff->skb)
- continue;
- dma_unmap_single(&sdev->pdev->dev,
- dma_unmap_addr(buff, map_addr),
- dma_unmap_len(buff, map_len), DMA_TO_DEVICE);
- consume_skb(buff->skb);
- }
- dma_pool_destroy(txq->dma_pool);
- kfree(txq->txbuffs);
- }
- static int slic_init_rx_queue(struct slic_device *sdev)
- {
- struct slic_rx_queue *rxq = &sdev->rxq;
- struct slic_rx_buffer *buff;
- rxq->len = SLIC_NUM_RX_LES;
- rxq->done_idx = 0;
- rxq->put_idx = 0;
- buff = kcalloc(rxq->len, sizeof(*buff), GFP_KERNEL);
- if (!buff)
- return -ENOMEM;
- rxq->rxbuffs = buff;
- slic_refill_rx_queue(sdev, GFP_KERNEL);
- return 0;
- }
- static void slic_free_rx_queue(struct slic_device *sdev)
- {
- struct slic_rx_queue *rxq = &sdev->rxq;
- struct slic_rx_buffer *buff;
- unsigned int i;
- /* free rx buffers */
- for (i = 0; i < rxq->len; i++) {
- buff = &rxq->rxbuffs[i];
- if (!buff->skb)
- continue;
- dma_unmap_single(&sdev->pdev->dev,
- dma_unmap_addr(buff, map_addr),
- dma_unmap_len(buff, map_len),
- DMA_FROM_DEVICE);
- consume_skb(buff->skb);
- }
- kfree(rxq->rxbuffs);
- }
- static void slic_set_link_autoneg(struct slic_device *sdev)
- {
- unsigned int subid = sdev->pdev->subsystem_device;
- u32 val;
- if (sdev->is_fiber) {
- /* We've got a fiber gigabit interface, and register 4 is
- * different in fiber mode than in copper mode.
- */
- /* advertise FD only @1000 Mb */
- val = MII_ADVERTISE << 16 | ADVERTISE_1000XFULL |
- ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
- /* enable PAUSE frames */
- slic_write(sdev, SLIC_REG_WPHY, val);
- /* reset phy, enable auto-neg */
- val = MII_BMCR << 16 | BMCR_RESET | BMCR_ANENABLE |
- BMCR_ANRESTART;
- slic_write(sdev, SLIC_REG_WPHY, val);
- } else { /* copper gigabit */
- /* We've got a copper gigabit interface, and register 4 is
- * different in copper mode than in fiber mode.
- */
- /* advertise 10/100 Mb modes */
- val = MII_ADVERTISE << 16 | ADVERTISE_100FULL |
- ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF;
- /* enable PAUSE frames */
- val |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
- /* required by the Cicada PHY */
- val |= ADVERTISE_CSMA;
- slic_write(sdev, SLIC_REG_WPHY, val);
- /* advertise FD only @1000 Mb */
- val = MII_CTRL1000 << 16 | ADVERTISE_1000FULL;
- slic_write(sdev, SLIC_REG_WPHY, val);
- if (subid != PCI_SUBDEVICE_ID_ALACRITECH_CICADA) {
- /* if a Marvell PHY enable auto crossover */
- val = SLIC_MIICR_REG_16 | SLIC_MRV_REG16_XOVERON;
- slic_write(sdev, SLIC_REG_WPHY, val);
- /* reset phy, enable auto-neg */
- val = MII_BMCR << 16 | BMCR_RESET | BMCR_ANENABLE |
- BMCR_ANRESTART;
- slic_write(sdev, SLIC_REG_WPHY, val);
- } else {
- /* enable and restart auto-neg (don't reset) */
- val = MII_BMCR << 16 | BMCR_ANENABLE | BMCR_ANRESTART;
- slic_write(sdev, SLIC_REG_WPHY, val);
- }
- }
- }
- static void slic_set_mac_address(struct slic_device *sdev)
- {
- const u8 *addr = sdev->netdev->dev_addr;
- u32 val;
- val = addr[5] | addr[4] << 8 | addr[3] << 16 | addr[2] << 24;
- slic_write(sdev, SLIC_REG_WRADDRAL, val);
- slic_write(sdev, SLIC_REG_WRADDRBL, val);
- val = addr[0] << 8 | addr[1];
- slic_write(sdev, SLIC_REG_WRADDRAH, val);
- slic_write(sdev, SLIC_REG_WRADDRBH, val);
- slic_flush_write(sdev);
- }
- static u32 slic_read_dword_from_firmware(const struct firmware *fw, int *offset)
- {
- int idx = *offset;
- __le32 val;
- memcpy(&val, fw->data + *offset, sizeof(val));
- idx += 4;
- *offset = idx;
- return le32_to_cpu(val);
- }
- MODULE_FIRMWARE(SLIC_RCV_FIRMWARE_MOJAVE);
- MODULE_FIRMWARE(SLIC_RCV_FIRMWARE_OASIS);
- static int slic_load_rcvseq_firmware(struct slic_device *sdev)
- {
- const struct firmware *fw;
- const char *file;
- u32 codelen;
- int idx = 0;
- u32 instr;
- u32 addr;
- int err;
- file = (sdev->model == SLIC_MODEL_OASIS) ? SLIC_RCV_FIRMWARE_OASIS :
- SLIC_RCV_FIRMWARE_MOJAVE;
- err = request_firmware(&fw, file, &sdev->pdev->dev);
- if (err) {
- dev_err(&sdev->pdev->dev,
- "failed to load receive sequencer firmware %s\n", file);
- return err;
- }
- /* Do an initial sanity check concerning firmware size now. A further
- * check follows below.
- */
- if (fw->size < SLIC_FIRMWARE_MIN_SIZE) {
- dev_err(&sdev->pdev->dev,
- "invalid firmware size %zu (min %u expected)\n",
- fw->size, SLIC_FIRMWARE_MIN_SIZE);
- err = -EINVAL;
- goto release;
- }
- codelen = slic_read_dword_from_firmware(fw, &idx);
- /* do another sanity check against firmware size */
- if ((codelen + 4) > fw->size) {
- dev_err(&sdev->pdev->dev,
- "invalid rcv-sequencer firmware size %zu\n", fw->size);
- err = -EINVAL;
- goto release;
- }
- /* download sequencer code to card */
- slic_write(sdev, SLIC_REG_RCV_WCS, SLIC_RCVWCS_BEGIN);
- for (addr = 0; addr < codelen; addr++) {
- __le32 val;
- /* write out instruction address */
- slic_write(sdev, SLIC_REG_RCV_WCS, addr);
- instr = slic_read_dword_from_firmware(fw, &idx);
- /* write out the instruction data low addr */
- slic_write(sdev, SLIC_REG_RCV_WCS, instr);
- val = (__le32)fw->data[idx];
- instr = le32_to_cpu(val);
- idx++;
- /* write out the instruction data high addr */
- slic_write(sdev, SLIC_REG_RCV_WCS, instr);
- }
- /* finish download */
- slic_write(sdev, SLIC_REG_RCV_WCS, SLIC_RCVWCS_FINISH);
- slic_flush_write(sdev);
- release:
- release_firmware(fw);
- return err;
- }
- MODULE_FIRMWARE(SLIC_FIRMWARE_MOJAVE);
- MODULE_FIRMWARE(SLIC_FIRMWARE_OASIS);
- static int slic_load_firmware(struct slic_device *sdev)
- {
- u32 sectstart[SLIC_FIRMWARE_MAX_SECTIONS];
- u32 sectsize[SLIC_FIRMWARE_MAX_SECTIONS];
- const struct firmware *fw;
- unsigned int datalen;
- const char *file;
- int code_start;
- unsigned int i;
- u32 numsects;
- int idx = 0;
- u32 sect;
- u32 instr;
- u32 addr;
- u32 base;
- int err;
- file = (sdev->model == SLIC_MODEL_OASIS) ? SLIC_FIRMWARE_OASIS :
- SLIC_FIRMWARE_MOJAVE;
- err = request_firmware(&fw, file, &sdev->pdev->dev);
- if (err) {
- dev_err(&sdev->pdev->dev, "failed to load firmware %s\n", file);
- return err;
- }
- /* Do an initial sanity check concerning firmware size now. A further
- * check follows below.
- */
- if (fw->size < SLIC_FIRMWARE_MIN_SIZE) {
- dev_err(&sdev->pdev->dev,
- "invalid firmware size %zu (min is %u)\n", fw->size,
- SLIC_FIRMWARE_MIN_SIZE);
- err = -EINVAL;
- goto release;
- }
- numsects = slic_read_dword_from_firmware(fw, &idx);
- if (numsects == 0 || numsects > SLIC_FIRMWARE_MAX_SECTIONS) {
- dev_err(&sdev->pdev->dev,
- "invalid number of sections in firmware: %u", numsects);
- err = -EINVAL;
- goto release;
- }
- datalen = numsects * 8 + 4;
- for (i = 0; i < numsects; i++) {
- sectsize[i] = slic_read_dword_from_firmware(fw, &idx);
- datalen += sectsize[i];
- }
- /* do another sanity check against firmware size */
- if (datalen > fw->size) {
- dev_err(&sdev->pdev->dev,
- "invalid firmware size %zu (expected >= %u)\n",
- fw->size, datalen);
- err = -EINVAL;
- goto release;
- }
- /* get sections */
- for (i = 0; i < numsects; i++)
- sectstart[i] = slic_read_dword_from_firmware(fw, &idx);
- code_start = idx;
- instr = slic_read_dword_from_firmware(fw, &idx);
- for (sect = 0; sect < numsects; sect++) {
- unsigned int ssize = sectsize[sect] >> 3;
- base = sectstart[sect];
- for (addr = 0; addr < ssize; addr++) {
- /* write out instruction address */
- slic_write(sdev, SLIC_REG_WCS, base + addr);
- /* write out instruction to low addr */
- slic_write(sdev, SLIC_REG_WCS, instr);
- instr = slic_read_dword_from_firmware(fw, &idx);
- /* write out instruction to high addr */
- slic_write(sdev, SLIC_REG_WCS, instr);
- instr = slic_read_dword_from_firmware(fw, &idx);
- }
- }
- idx = code_start;
- for (sect = 0; sect < numsects; sect++) {
- unsigned int ssize = sectsize[sect] >> 3;
- instr = slic_read_dword_from_firmware(fw, &idx);
- base = sectstart[sect];
- if (base < 0x8000)
- continue;
- for (addr = 0; addr < ssize; addr++) {
- /* write out instruction address */
- slic_write(sdev, SLIC_REG_WCS,
- SLIC_WCS_COMPARE | (base + addr));
- /* write out instruction to low addr */
- slic_write(sdev, SLIC_REG_WCS, instr);
- instr = slic_read_dword_from_firmware(fw, &idx);
- /* write out instruction to high addr */
- slic_write(sdev, SLIC_REG_WCS, instr);
- instr = slic_read_dword_from_firmware(fw, &idx);
- }
- }
- slic_flush_write(sdev);
- mdelay(10);
- /* everything OK, kick off the card */
- slic_write(sdev, SLIC_REG_WCS, SLIC_WCS_START);
- slic_flush_write(sdev);
- /* wait long enough for ucode to init card and reach the mainloop */
- mdelay(20);
- release:
- release_firmware(fw);
- return err;
- }
- static int slic_init_shmem(struct slic_device *sdev)
- {
- struct slic_shmem *sm = &sdev->shmem;
- struct slic_shmem_data *sm_data;
- dma_addr_t paddr;
- sm_data = dma_alloc_coherent(&sdev->pdev->dev, sizeof(*sm_data),
- &paddr, GFP_KERNEL);
- if (!sm_data) {
- dev_err(&sdev->pdev->dev, "failed to allocate shared memory\n");
- return -ENOMEM;
- }
- sm->shmem_data = sm_data;
- sm->isr_paddr = paddr;
- sm->link_paddr = paddr + offsetof(struct slic_shmem_data, link);
- return 0;
- }
- static void slic_free_shmem(struct slic_device *sdev)
- {
- struct slic_shmem *sm = &sdev->shmem;
- struct slic_shmem_data *sm_data = sm->shmem_data;
- dma_free_coherent(&sdev->pdev->dev, sizeof(*sm_data), sm_data,
- sm->isr_paddr);
- }
- static int slic_init_iface(struct slic_device *sdev)
- {
- struct slic_shmem *sm = &sdev->shmem;
- int err;
- sdev->upr_list.pending = false;
- err = slic_init_shmem(sdev);
- if (err) {
- netdev_err(sdev->netdev, "failed to init shared memory\n");
- return err;
- }
- err = slic_load_firmware(sdev);
- if (err) {
- netdev_err(sdev->netdev, "failed to load firmware\n");
- goto free_sm;
- }
- err = slic_load_rcvseq_firmware(sdev);
- if (err) {
- netdev_err(sdev->netdev,
- "failed to load firmware for receive sequencer\n");
- goto free_sm;
- }
- slic_write(sdev, SLIC_REG_ICR, SLIC_ICR_INT_OFF);
- slic_flush_write(sdev);
- mdelay(1);
- err = slic_init_rx_queue(sdev);
- if (err) {
- netdev_err(sdev->netdev, "failed to init rx queue: %u\n", err);
- goto free_sm;
- }
- err = slic_init_tx_queue(sdev);
- if (err) {
- netdev_err(sdev->netdev, "failed to init tx queue: %u\n", err);
- goto free_rxq;
- }
- err = slic_init_stat_queue(sdev);
- if (err) {
- netdev_err(sdev->netdev, "failed to init status queue: %u\n",
- err);
- goto free_txq;
- }
- slic_write(sdev, SLIC_REG_ISP, lower_32_bits(sm->isr_paddr));
- napi_enable(&sdev->napi);
- /* disable irq mitigation */
- slic_write(sdev, SLIC_REG_INTAGG, 0);
- slic_write(sdev, SLIC_REG_ISR, 0);
- slic_flush_write(sdev);
- slic_set_mac_address(sdev);
- spin_lock_bh(&sdev->link_lock);
- sdev->duplex = DUPLEX_UNKNOWN;
- sdev->speed = SPEED_UNKNOWN;
- spin_unlock_bh(&sdev->link_lock);
- slic_set_link_autoneg(sdev);
- err = request_irq(sdev->pdev->irq, slic_irq, IRQF_SHARED, DRV_NAME,
- sdev);
- if (err) {
- netdev_err(sdev->netdev, "failed to request irq: %u\n", err);
- goto disable_napi;
- }
- slic_write(sdev, SLIC_REG_ICR, SLIC_ICR_INT_ON);
- slic_flush_write(sdev);
- /* request initial link status */
- err = slic_handle_link_change(sdev);
- if (err)
- netdev_warn(sdev->netdev,
- "failed to set initial link state: %u\n", err);
- return 0;
- disable_napi:
- napi_disable(&sdev->napi);
- slic_free_stat_queue(sdev);
- free_txq:
- slic_free_tx_queue(sdev);
- free_rxq:
- slic_free_rx_queue(sdev);
- free_sm:
- slic_free_shmem(sdev);
- slic_card_reset(sdev);
- return err;
- }
- static int slic_open(struct net_device *dev)
- {
- struct slic_device *sdev = netdev_priv(dev);
- int err;
- netif_carrier_off(dev);
- err = slic_init_iface(sdev);
- if (err) {
- netdev_err(dev, "failed to initialize interface: %i\n", err);
- return err;
- }
- netif_start_queue(dev);
- return 0;
- }
- static int slic_close(struct net_device *dev)
- {
- struct slic_device *sdev = netdev_priv(dev);
- u32 val;
- netif_stop_queue(dev);
- /* stop irq handling */
- napi_disable(&sdev->napi);
- slic_write(sdev, SLIC_REG_ICR, SLIC_ICR_INT_OFF);
- slic_write(sdev, SLIC_REG_ISR, 0);
- slic_flush_write(sdev);
- free_irq(sdev->pdev->irq, sdev);
- /* turn off RCV and XMT and power down PHY */
- val = SLIC_GXCR_RESET | SLIC_GXCR_PAUSEEN;
- slic_write(sdev, SLIC_REG_WXCFG, val);
- val = SLIC_GRCR_RESET | SLIC_GRCR_CTLEN | SLIC_GRCR_ADDRAEN |
- SLIC_GRCR_HASHSIZE << SLIC_GRCR_HASHSIZE_SHIFT;
- slic_write(sdev, SLIC_REG_WRCFG, val);
- val = MII_BMCR << 16 | BMCR_PDOWN;
- slic_write(sdev, SLIC_REG_WPHY, val);
- slic_flush_write(sdev);
- slic_clear_upr_list(&sdev->upr_list);
- slic_write(sdev, SLIC_REG_QUIESCE, 0);
- slic_free_stat_queue(sdev);
- slic_free_tx_queue(sdev);
- slic_free_rx_queue(sdev);
- slic_free_shmem(sdev);
- slic_card_reset(sdev);
- netif_carrier_off(dev);
- return 0;
- }
- static netdev_tx_t slic_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct slic_device *sdev = netdev_priv(dev);
- struct slic_tx_queue *txq = &sdev->txq;
- struct slic_tx_buffer *buff;
- struct slic_tx_desc *desc;
- dma_addr_t paddr;
- u32 cbar_val;
- u32 maplen;
- if (unlikely(slic_get_free_tx_descs(txq) < SLIC_MAX_REQ_TX_DESCS)) {
- netdev_err(dev, "BUG! not enough tx LEs left: %u\n",
- slic_get_free_tx_descs(txq));
- return NETDEV_TX_BUSY;
- }
- maplen = skb_headlen(skb);
- paddr = dma_map_single(&sdev->pdev->dev, skb->data, maplen,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&sdev->pdev->dev, paddr)) {
- netdev_err(dev, "failed to map tx buffer\n");
- goto drop_skb;
- }
- buff = &txq->txbuffs[txq->put_idx];
- buff->skb = skb;
- dma_unmap_addr_set(buff, map_addr, paddr);
- dma_unmap_len_set(buff, map_len, maplen);
- desc = buff->desc;
- desc->totlen = cpu_to_le32(maplen);
- desc->paddrl = cpu_to_le32(lower_32_bits(paddr));
- desc->paddrh = cpu_to_le32(upper_32_bits(paddr));
- desc->len = cpu_to_le32(maplen);
- txq->put_idx = slic_next_queue_idx(txq->put_idx, txq->len);
- cbar_val = lower_32_bits(buff->desc_paddr) | 1;
- /* complete writes to RAM and DMA before hardware is informed */
- wmb();
- slic_write(sdev, SLIC_REG_CBAR, cbar_val);
- if (slic_get_free_tx_descs(txq) < SLIC_MAX_REQ_TX_DESCS)
- netif_stop_queue(dev);
- return NETDEV_TX_OK;
- drop_skb:
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
- static void slic_get_stats(struct net_device *dev,
- struct rtnl_link_stats64 *lst)
- {
- struct slic_device *sdev = netdev_priv(dev);
- struct slic_stats *stats = &sdev->stats;
- SLIC_GET_STATS_COUNTER(lst->rx_packets, stats, rx_packets);
- SLIC_GET_STATS_COUNTER(lst->tx_packets, stats, tx_packets);
- SLIC_GET_STATS_COUNTER(lst->rx_bytes, stats, rx_bytes);
- SLIC_GET_STATS_COUNTER(lst->tx_bytes, stats, tx_bytes);
- SLIC_GET_STATS_COUNTER(lst->rx_errors, stats, rx_errors);
- SLIC_GET_STATS_COUNTER(lst->rx_dropped, stats, rx_buff_miss);
- SLIC_GET_STATS_COUNTER(lst->tx_dropped, stats, tx_dropped);
- SLIC_GET_STATS_COUNTER(lst->multicast, stats, rx_mcasts);
- SLIC_GET_STATS_COUNTER(lst->rx_over_errors, stats, rx_buffoflow);
- SLIC_GET_STATS_COUNTER(lst->rx_crc_errors, stats, rx_crc);
- SLIC_GET_STATS_COUNTER(lst->rx_fifo_errors, stats, rx_oflow802);
- SLIC_GET_STATS_COUNTER(lst->tx_carrier_errors, stats, tx_carrier);
- }
- static int slic_get_sset_count(struct net_device *dev, int sset)
- {
- switch (sset) {
- case ETH_SS_STATS:
- return ARRAY_SIZE(slic_stats_strings);
- default:
- return -EOPNOTSUPP;
- }
- }
- static void slic_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *eth_stats, u64 *data)
- {
- struct slic_device *sdev = netdev_priv(dev);
- struct slic_stats *stats = &sdev->stats;
- SLIC_GET_STATS_COUNTER(data[0], stats, rx_packets);
- SLIC_GET_STATS_COUNTER(data[1], stats, rx_bytes);
- SLIC_GET_STATS_COUNTER(data[2], stats, rx_mcasts);
- SLIC_GET_STATS_COUNTER(data[3], stats, rx_errors);
- SLIC_GET_STATS_COUNTER(data[4], stats, rx_buff_miss);
- SLIC_GET_STATS_COUNTER(data[5], stats, rx_tpcsum);
- SLIC_GET_STATS_COUNTER(data[6], stats, rx_tpoflow);
- SLIC_GET_STATS_COUNTER(data[7], stats, rx_tphlen);
- SLIC_GET_STATS_COUNTER(data[8], stats, rx_ipcsum);
- SLIC_GET_STATS_COUNTER(data[9], stats, rx_iplen);
- SLIC_GET_STATS_COUNTER(data[10], stats, rx_iphlen);
- SLIC_GET_STATS_COUNTER(data[11], stats, rx_early);
- SLIC_GET_STATS_COUNTER(data[12], stats, rx_buffoflow);
- SLIC_GET_STATS_COUNTER(data[13], stats, rx_lcode);
- SLIC_GET_STATS_COUNTER(data[14], stats, rx_drbl);
- SLIC_GET_STATS_COUNTER(data[15], stats, rx_crc);
- SLIC_GET_STATS_COUNTER(data[16], stats, rx_oflow802);
- SLIC_GET_STATS_COUNTER(data[17], stats, rx_uflow802);
- SLIC_GET_STATS_COUNTER(data[18], stats, tx_packets);
- SLIC_GET_STATS_COUNTER(data[19], stats, tx_bytes);
- SLIC_GET_STATS_COUNTER(data[20], stats, tx_carrier);
- SLIC_GET_STATS_COUNTER(data[21], stats, tx_dropped);
- SLIC_GET_STATS_COUNTER(data[22], stats, irq_errs);
- }
- static void slic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
- {
- if (stringset == ETH_SS_STATS) {
- memcpy(data, slic_stats_strings, sizeof(slic_stats_strings));
- data += sizeof(slic_stats_strings);
- }
- }
- static void slic_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
- {
- struct slic_device *sdev = netdev_priv(dev);
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->bus_info, pci_name(sdev->pdev), sizeof(info->bus_info));
- }
- static const struct ethtool_ops slic_ethtool_ops = {
- .get_drvinfo = slic_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_strings = slic_get_strings,
- .get_ethtool_stats = slic_get_ethtool_stats,
- .get_sset_count = slic_get_sset_count,
- };
- static const struct net_device_ops slic_netdev_ops = {
- .ndo_open = slic_open,
- .ndo_stop = slic_close,
- .ndo_start_xmit = slic_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_get_stats64 = slic_get_stats,
- .ndo_set_rx_mode = slic_set_rx_mode,
- .ndo_validate_addr = eth_validate_addr,
- };
- static u16 slic_eeprom_csum(unsigned char *eeprom, unsigned int len)
- {
- unsigned char *ptr = eeprom;
- u32 csum = 0;
- __le16 data;
- while (len > 1) {
- memcpy(&data, ptr, sizeof(data));
- csum += le16_to_cpu(data);
- ptr += 2;
- len -= 2;
- }
- if (len > 0)
- csum += *(u8 *)ptr;
- while (csum >> 16)
- csum = (csum & 0xFFFF) + ((csum >> 16) & 0xFFFF);
- return ~csum;
- }
- /* check eeprom size, magic and checksum */
- static bool slic_eeprom_valid(unsigned char *eeprom, unsigned int size)
- {
- const unsigned int MAX_SIZE = 128;
- const unsigned int MIN_SIZE = 98;
- __le16 magic;
- __le16 csum;
- if (size < MIN_SIZE || size > MAX_SIZE)
- return false;
- memcpy(&magic, eeprom, sizeof(magic));
- if (le16_to_cpu(magic) != SLIC_EEPROM_MAGIC)
- return false;
- /* cut checksum bytes */
- size -= 2;
- memcpy(&csum, eeprom + size, sizeof(csum));
- return (le16_to_cpu(csum) == slic_eeprom_csum(eeprom, size));
- }
- static int slic_read_eeprom(struct slic_device *sdev)
- {
- unsigned int devfn = PCI_FUNC(sdev->pdev->devfn);
- struct slic_shmem *sm = &sdev->shmem;
- struct slic_shmem_data *sm_data = sm->shmem_data;
- const unsigned int MAX_LOOPS = 5000;
- unsigned int codesize;
- unsigned char *eeprom;
- struct slic_upr *upr;
- unsigned int i = 0;
- dma_addr_t paddr;
- int err = 0;
- u8 *mac[2];
- eeprom = dma_alloc_coherent(&sdev->pdev->dev, SLIC_EEPROM_SIZE,
- &paddr, GFP_KERNEL);
- if (!eeprom)
- return -ENOMEM;
- slic_write(sdev, SLIC_REG_ICR, SLIC_ICR_INT_OFF);
- /* setup ISP temporarily */
- slic_write(sdev, SLIC_REG_ISP, lower_32_bits(sm->isr_paddr));
- err = slic_new_upr(sdev, SLIC_UPR_CONFIG, paddr);
- if (!err) {
- for (i = 0; i < MAX_LOOPS; i++) {
- if (le32_to_cpu(sm_data->isr) & SLIC_ISR_UPC)
- break;
- mdelay(1);
- }
- if (i == MAX_LOOPS) {
- dev_err(&sdev->pdev->dev,
- "timed out while waiting for eeprom data\n");
- err = -ETIMEDOUT;
- }
- upr = slic_dequeue_upr(sdev);
- kfree(upr);
- }
- slic_write(sdev, SLIC_REG_ISP, 0);
- slic_write(sdev, SLIC_REG_ISR, 0);
- slic_flush_write(sdev);
- if (err)
- goto free_eeprom;
- if (sdev->model == SLIC_MODEL_OASIS) {
- struct slic_oasis_eeprom *oee;
- oee = (struct slic_oasis_eeprom *)eeprom;
- mac[0] = oee->mac;
- mac[1] = oee->mac2;
- codesize = le16_to_cpu(oee->eeprom_code_size);
- } else {
- struct slic_mojave_eeprom *mee;
- mee = (struct slic_mojave_eeprom *)eeprom;
- mac[0] = mee->mac;
- mac[1] = mee->mac2;
- codesize = le16_to_cpu(mee->eeprom_code_size);
- }
- if (!slic_eeprom_valid(eeprom, codesize)) {
- dev_err(&sdev->pdev->dev, "invalid checksum in eeprom\n");
- err = -EINVAL;
- goto free_eeprom;
- }
- /* set mac address */
- eth_hw_addr_set(sdev->netdev, mac[devfn]);
- free_eeprom:
- dma_free_coherent(&sdev->pdev->dev, SLIC_EEPROM_SIZE, eeprom, paddr);
- return err;
- }
- static int slic_init(struct slic_device *sdev)
- {
- int err;
- spin_lock_init(&sdev->upper_lock);
- spin_lock_init(&sdev->link_lock);
- INIT_LIST_HEAD(&sdev->upr_list.list);
- spin_lock_init(&sdev->upr_list.lock);
- u64_stats_init(&sdev->stats.syncp);
- slic_card_reset(sdev);
- err = slic_load_firmware(sdev);
- if (err) {
- dev_err(&sdev->pdev->dev, "failed to load firmware\n");
- return err;
- }
- /* we need the shared memory to read EEPROM so set it up temporarily */
- err = slic_init_shmem(sdev);
- if (err) {
- dev_err(&sdev->pdev->dev, "failed to init shared memory\n");
- return err;
- }
- err = slic_read_eeprom(sdev);
- if (err) {
- dev_err(&sdev->pdev->dev, "failed to read eeprom\n");
- goto free_sm;
- }
- slic_card_reset(sdev);
- slic_free_shmem(sdev);
- return 0;
- free_sm:
- slic_free_shmem(sdev);
- return err;
- }
- static bool slic_is_fiber(unsigned short subdev)
- {
- switch (subdev) {
- /* Mojave */
- case PCI_SUBDEVICE_ID_ALACRITECH_1000X1F:
- case PCI_SUBDEVICE_ID_ALACRITECH_SES1001F: fallthrough;
- /* Oasis */
- case PCI_SUBDEVICE_ID_ALACRITECH_SEN2002XF:
- case PCI_SUBDEVICE_ID_ALACRITECH_SEN2001XF:
- case PCI_SUBDEVICE_ID_ALACRITECH_SEN2104EF:
- case PCI_SUBDEVICE_ID_ALACRITECH_SEN2102EF:
- return true;
- }
- return false;
- }
- static void slic_configure_pci(struct pci_dev *pdev)
- {
- u16 old;
- u16 cmd;
- pci_read_config_word(pdev, PCI_COMMAND, &old);
- cmd = old | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
- if (old != cmd)
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- }
- static int slic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- {
- struct slic_device *sdev;
- struct net_device *dev;
- int err;
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "failed to enable PCI device\n");
- return err;
- }
- pci_set_master(pdev);
- pci_try_set_mwi(pdev);
- slic_configure_pci(pdev);
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- dev_err(&pdev->dev, "failed to setup DMA\n");
- goto disable;
- }
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- err = pci_request_regions(pdev, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "failed to obtain PCI regions\n");
- goto disable;
- }
- dev = alloc_etherdev(sizeof(*sdev));
- if (!dev) {
- dev_err(&pdev->dev, "failed to alloc ethernet device\n");
- err = -ENOMEM;
- goto free_regions;
- }
- SET_NETDEV_DEV(dev, &pdev->dev);
- pci_set_drvdata(pdev, dev);
- dev->irq = pdev->irq;
- dev->netdev_ops = &slic_netdev_ops;
- dev->hw_features = NETIF_F_RXCSUM;
- dev->features |= dev->hw_features;
- dev->ethtool_ops = &slic_ethtool_ops;
- sdev = netdev_priv(dev);
- sdev->model = (pdev->device == PCI_DEVICE_ID_ALACRITECH_OASIS) ?
- SLIC_MODEL_OASIS : SLIC_MODEL_MOJAVE;
- sdev->is_fiber = slic_is_fiber(pdev->subsystem_device);
- sdev->pdev = pdev;
- sdev->netdev = dev;
- sdev->regs = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!sdev->regs) {
- dev_err(&pdev->dev, "failed to map registers\n");
- err = -ENOMEM;
- goto free_netdev;
- }
- err = slic_init(sdev);
- if (err) {
- dev_err(&pdev->dev, "failed to initialize driver\n");
- goto unmap;
- }
- netif_napi_add(dev, &sdev->napi, slic_poll);
- netif_carrier_off(dev);
- err = register_netdev(dev);
- if (err) {
- dev_err(&pdev->dev, "failed to register net device: %i\n", err);
- goto unmap;
- }
- return 0;
- unmap:
- iounmap(sdev->regs);
- free_netdev:
- free_netdev(dev);
- free_regions:
- pci_release_regions(pdev);
- disable:
- pci_disable_device(pdev);
- return err;
- }
- static void slic_remove(struct pci_dev *pdev)
- {
- struct net_device *dev = pci_get_drvdata(pdev);
- struct slic_device *sdev = netdev_priv(dev);
- unregister_netdev(dev);
- iounmap(sdev->regs);
- free_netdev(dev);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- }
- static struct pci_driver slic_driver = {
- .name = DRV_NAME,
- .id_table = slic_id_tbl,
- .probe = slic_probe,
- .remove = slic_remove,
- };
- module_pci_driver(slic_driver);
- MODULE_DESCRIPTION("Alacritech non-accelerated SLIC driver");
- MODULE_AUTHOR("Lino Sanfilippo <[email protected]>");
- MODULE_LICENSE("GPL");
|