brintos

brintos / linux-shallow public Read only

0
0
Text · 12.4 KiB · 5d6d282 Raw
516 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh3 * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh4 */5 6#include <linux/can/dev.h>7#include <linux/can.h>8#include <linux/can/netlink.h>9#include <linux/delay.h>10#include <linux/dma-mapping.h>11#include <linux/ethtool.h>12#include <linux/interrupt.h>13#include <linux/io.h>14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/netdevice.h>17#include <linux/pci.h>18 19#include "esdacc.h"20 21#define ESD_PCI_DEVICE_ID_PCIE402 0x040222 23#define PCI402_FPGA_VER_MIN 0x003d24#define PCI402_MAX_CORES 625#define PCI402_BAR 026#define PCI402_IO_OV_OFFS 027#define PCI402_IO_PCIEP_OFFS 0x1000028#define PCI402_IO_LEN_TOTAL 0x2000029#define PCI402_IO_LEN_CORE 0x200030#define PCI402_PCICFG_MSICAP 0x5031 32#define PCI402_DMA_MASK DMA_BIT_MASK(32)33#define PCI402_DMA_SIZE ALIGN(0x10000, PAGE_SIZE)34 35#define PCI402_PCIEP_OF_INT_ENABLE 0x005036#define PCI402_PCIEP_OF_BM_ADDR_LO 0x100037#define PCI402_PCIEP_OF_BM_ADDR_HI 0x100438#define PCI402_PCIEP_OF_MSI_ADDR_LO 0x100839#define PCI402_PCIEP_OF_MSI_ADDR_HI 0x100c40 41struct pci402_card {42	/* Actually mapped io space, all other iomem derived from this */43	void __iomem *addr;44	void __iomem *addr_pciep;45 46	void *dma_buf;47	dma_addr_t dma_hnd;48 49	struct acc_ov ov;50	struct acc_core *cores;51 52	bool msi_enabled;53};54 55/* The BTR register capabilities described by the can_bittiming_const structures56 * below are valid since esdACC version 0x0032.57 */58 59/* Used if the esdACC FPGA is built as CAN-Classic version. */60static const struct can_bittiming_const pci402_bittiming_const = {61	.name = "esd_402",62	.tseg1_min = 1,63	.tseg1_max = 16,64	.tseg2_min = 1,65	.tseg2_max = 8,66	.sjw_max = 4,67	.brp_min = 1,68	.brp_max = 512,69	.brp_inc = 1,70};71 72/* Used if the esdACC FPGA is built as CAN-FD version. */73static const struct can_bittiming_const pci402_bittiming_const_canfd = {74	.name = "esd_402fd",75	.tseg1_min = 1,76	.tseg1_max = 256,77	.tseg2_min = 1,78	.tseg2_max = 128,79	.sjw_max = 128,80	.brp_min = 1,81	.brp_max = 256,82	.brp_inc = 1,83};84 85static const struct net_device_ops pci402_acc_netdev_ops = {86	.ndo_open = acc_open,87	.ndo_stop = acc_close,88	.ndo_start_xmit = acc_start_xmit,89	.ndo_change_mtu = can_change_mtu,90	.ndo_eth_ioctl = can_eth_ioctl_hwts,91};92 93static const struct ethtool_ops pci402_acc_ethtool_ops = {94	.get_ts_info = can_ethtool_op_get_ts_info_hwts,95};96 97static irqreturn_t pci402_interrupt(int irq, void *dev_id)98{99	struct pci_dev *pdev = dev_id;100	struct pci402_card *card = pci_get_drvdata(pdev);101	irqreturn_t irq_status;102 103	irq_status = acc_card_interrupt(&card->ov, card->cores);104 105	return irq_status;106}107 108static int pci402_set_msiconfig(struct pci_dev *pdev)109{110	struct pci402_card *card = pci_get_drvdata(pdev);111	u32 addr_lo_offs = 0;112	u32 addr_lo = 0;113	u32 addr_hi = 0;114	u32 data = 0;115	u16 csr = 0;116	int err;117 118	/* The FPGA hard IP PCIe core implements a 64-bit MSI Capability119	 * Register Format120	 */121	err = pci_read_config_word(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_FLAGS, &csr);122	if (err)123		goto failed;124 125	err = pci_read_config_dword(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_ADDRESS_LO,126				    &addr_lo);127	if (err)128		goto failed;129	err = pci_read_config_dword(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_ADDRESS_HI,130				    &addr_hi);131	if (err)132		goto failed;133 134	err = pci_read_config_dword(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_DATA_64,135				    &data);136	if (err)137		goto failed;138 139	addr_lo_offs = addr_lo & 0x0000ffff;140	addr_lo &= 0xffff0000;141 142	if (addr_hi)143		addr_lo |= 1; /* To enable 64-Bit addressing in PCIe endpoint */144 145	if (!(csr & PCI_MSI_FLAGS_ENABLE)) {146		err = -EINVAL;147		goto failed;148	}149 150	iowrite32(addr_lo, card->addr_pciep + PCI402_PCIEP_OF_MSI_ADDR_LO);151	iowrite32(addr_hi, card->addr_pciep + PCI402_PCIEP_OF_MSI_ADDR_HI);152	acc_ov_write32(&card->ov, ACC_OV_OF_MSI_ADDRESSOFFSET, addr_lo_offs);153	acc_ov_write32(&card->ov, ACC_OV_OF_MSI_DATA, data);154 155	return 0;156 157failed:158	pci_warn(pdev, "Error while setting MSI configuration:\n"159		 "CSR: 0x%.4x, addr: 0x%.8x%.8x, offs: 0x%.4x, data: 0x%.8x\n",160		 csr, addr_hi, addr_lo, addr_lo_offs, data);161 162	return err;163}164 165static int pci402_init_card(struct pci_dev *pdev)166{167	struct pci402_card *card = pci_get_drvdata(pdev);168 169	card->ov.addr = card->addr + PCI402_IO_OV_OFFS;170	card->addr_pciep = card->addr + PCI402_IO_PCIEP_OFFS;171 172	acc_reset_fpga(&card->ov);173	acc_init_ov(&card->ov, &pdev->dev);174 175	if (card->ov.version < PCI402_FPGA_VER_MIN) {176		pci_err(pdev,177			"esdACC version (0x%.4x) outdated, please update\n",178			card->ov.version);179		return -EINVAL;180	}181 182	if (card->ov.timestamp_frequency != ACC_TS_FREQ_80MHZ) {183		pci_err(pdev,184			"esdACC timestamp frequency of %uHz not supported by driver. Aborted.\n",185			card->ov.timestamp_frequency);186		return -EINVAL;187	}188 189	if (card->ov.active_cores > PCI402_MAX_CORES) {190		pci_err(pdev,191			"Card with %u active cores not supported by driver. Aborted.\n",192			card->ov.active_cores);193		return -EINVAL;194	}195	card->cores = devm_kcalloc(&pdev->dev, card->ov.active_cores,196				   sizeof(struct acc_core), GFP_KERNEL);197	if (!card->cores)198		return -ENOMEM;199 200	if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD) {201		pci_warn(pdev,202			 "esdACC with CAN-FD feature detected. This driver doesn't support CAN-FD yet.\n");203	}204 205#ifdef __LITTLE_ENDIAN206	/* So card converts all busmastered data to LE for us: */207	acc_ov_set_bits(&card->ov, ACC_OV_OF_MODE,208			ACC_OV_REG_MODE_MASK_ENDIAN_LITTLE);209#endif210 211	return 0;212}213 214static int pci402_init_interrupt(struct pci_dev *pdev)215{216	struct pci402_card *card = pci_get_drvdata(pdev);217	int err;218 219	err = pci_enable_msi(pdev);220	if (!err) {221		err = pci402_set_msiconfig(pdev);222		if (!err) {223			card->msi_enabled = true;224			acc_ov_set_bits(&card->ov, ACC_OV_OF_MODE,225					ACC_OV_REG_MODE_MASK_MSI_ENABLE);226			pci_dbg(pdev, "MSI preparation done\n");227		}228	}229 230	err = devm_request_irq(&pdev->dev, pdev->irq, pci402_interrupt,231			       IRQF_SHARED, dev_name(&pdev->dev), pdev);232	if (err)233		goto failure_msidis;234 235	iowrite32(1, card->addr_pciep + PCI402_PCIEP_OF_INT_ENABLE);236 237	return 0;238 239failure_msidis:240	if (card->msi_enabled) {241		acc_ov_clear_bits(&card->ov, ACC_OV_OF_MODE,242				  ACC_OV_REG_MODE_MASK_MSI_ENABLE);243		pci_disable_msi(pdev);244		card->msi_enabled = false;245	}246 247	return err;248}249 250static void pci402_finish_interrupt(struct pci_dev *pdev)251{252	struct pci402_card *card = pci_get_drvdata(pdev);253 254	iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_INT_ENABLE);255	devm_free_irq(&pdev->dev, pdev->irq, pdev);256 257	if (card->msi_enabled) {258		acc_ov_clear_bits(&card->ov, ACC_OV_OF_MODE,259				  ACC_OV_REG_MODE_MASK_MSI_ENABLE);260		pci_disable_msi(pdev);261		card->msi_enabled = false;262	}263}264 265static int pci402_init_dma(struct pci_dev *pdev)266{267	struct pci402_card *card = pci_get_drvdata(pdev);268	int err;269 270	err = dma_set_coherent_mask(&pdev->dev, PCI402_DMA_MASK);271	if (err) {272		pci_err(pdev, "DMA set mask failed!\n");273		return err;274	}275 276	/* The esdACC DMA engine needs the DMA buffer aligned to a 64k277	 * boundary. The DMA API guarantees to align the returned buffer to the278	 * smallest PAGE_SIZE order which is greater than or equal to the279	 * requested size. With PCI402_DMA_SIZE == 64kB this suffices here.280	 */281	card->dma_buf = dma_alloc_coherent(&pdev->dev, PCI402_DMA_SIZE,282					   &card->dma_hnd, GFP_KERNEL);283	if (!card->dma_buf)284		return -ENOMEM;285 286	acc_init_bm_ptr(&card->ov, card->cores, card->dma_buf);287 288	iowrite32(card->dma_hnd,289		  card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_LO);290	iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_HI);291 292	pci_set_master(pdev);293 294	acc_ov_set_bits(&card->ov, ACC_OV_OF_MODE,295			ACC_OV_REG_MODE_MASK_BM_ENABLE);296 297	return 0;298}299 300static void pci402_finish_dma(struct pci_dev *pdev)301{302	struct pci402_card *card = pci_get_drvdata(pdev);303	int i;304 305	acc_ov_clear_bits(&card->ov, ACC_OV_OF_MODE,306			  ACC_OV_REG_MODE_MASK_BM_ENABLE);307 308	pci_clear_master(pdev);309 310	iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_LO);311	iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_HI);312 313	card->ov.bmfifo.messages = NULL;314	card->ov.bmfifo.irq_cnt = NULL;315	for (i = 0; i < card->ov.active_cores; i++) {316		struct acc_core *core = &card->cores[i];317 318		core->bmfifo.messages = NULL;319		core->bmfifo.irq_cnt = NULL;320	}321 322	dma_free_coherent(&pdev->dev, PCI402_DMA_SIZE, card->dma_buf,323			  card->dma_hnd);324	card->dma_buf = NULL;325}326 327static void pci402_unregister_core(struct acc_core *core)328{329	netdev_info(core->netdev, "unregister\n");330	unregister_candev(core->netdev);331 332	free_candev(core->netdev);333	core->netdev = NULL;334}335 336static int pci402_init_cores(struct pci_dev *pdev)337{338	struct pci402_card *card = pci_get_drvdata(pdev);339	int err;340	int i;341 342	for (i = 0; i < card->ov.active_cores; i++) {343		struct acc_core *core = &card->cores[i];344		struct acc_net_priv *priv;345		struct net_device *netdev;346		u32 fifo_config;347 348		core->addr = card->ov.addr + (i + 1) * PCI402_IO_LEN_CORE;349 350		fifo_config = acc_read32(core, ACC_CORE_OF_TXFIFO_CONFIG);351		core->tx_fifo_size = (fifo_config >> 24);352		if (core->tx_fifo_size <= 1) {353			pci_err(pdev, "Invalid tx_fifo_size!\n");354			err = -EINVAL;355			goto failure;356		}357 358		netdev = alloc_candev(sizeof(*priv), core->tx_fifo_size);359		if (!netdev) {360			err = -ENOMEM;361			goto failure;362		}363		core->netdev = netdev;364 365		netdev->flags |= IFF_ECHO;366		netdev->dev_port = i;367		netdev->netdev_ops = &pci402_acc_netdev_ops;368		netdev->ethtool_ops = &pci402_acc_ethtool_ops;369		SET_NETDEV_DEV(netdev, &pdev->dev);370 371		priv = netdev_priv(netdev);372		priv->can.clock.freq = card->ov.core_frequency;373		priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |374			CAN_CTRLMODE_LISTENONLY |375			CAN_CTRLMODE_BERR_REPORTING |376			CAN_CTRLMODE_CC_LEN8_DLC;377		if (card->ov.features & ACC_OV_REG_FEAT_MASK_DAR)378			priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;379		if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD)380			priv->can.bittiming_const = &pci402_bittiming_const_canfd;381		else382			priv->can.bittiming_const = &pci402_bittiming_const;383		priv->can.do_set_bittiming = acc_set_bittiming;384		priv->can.do_set_mode = acc_set_mode;385		priv->can.do_get_berr_counter = acc_get_berr_counter;386 387		priv->core = core;388		priv->ov = &card->ov;389 390		err = register_candev(netdev);391		if (err) {392			free_candev(core->netdev);393			core->netdev = NULL;394			goto failure;395		}396 397		netdev_info(netdev, "registered\n");398	}399 400	return 0;401 402failure:403	for (i--; i >= 0; i--)404		pci402_unregister_core(&card->cores[i]);405 406	return err;407}408 409static void pci402_finish_cores(struct pci_dev *pdev)410{411	struct pci402_card *card = pci_get_drvdata(pdev);412	int i;413 414	for (i = 0; i < card->ov.active_cores; i++)415		pci402_unregister_core(&card->cores[i]);416}417 418static int pci402_probe(struct pci_dev *pdev, const struct pci_device_id *ent)419{420	struct pci402_card *card = NULL;421	int err;422 423	err = pci_enable_device(pdev);424	if (err)425		return err;426 427	card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);428	if (!card) {429		err = -ENOMEM;430		goto failure_disable_pci;431	}432 433	pci_set_drvdata(pdev, card);434 435	err = pci_request_regions(pdev, pci_name(pdev));436	if (err)437		goto failure_disable_pci;438 439	card->addr = pci_iomap(pdev, PCI402_BAR, PCI402_IO_LEN_TOTAL);440	if (!card->addr) {441		err = -ENOMEM;442		goto failure_release_regions;443	}444 445	err = pci402_init_card(pdev);446	if (err)447		goto failure_unmap;448 449	err = pci402_init_dma(pdev);450	if (err)451		goto failure_unmap;452 453	err = pci402_init_interrupt(pdev);454	if (err)455		goto failure_finish_dma;456 457	err = pci402_init_cores(pdev);458	if (err)459		goto failure_finish_interrupt;460 461	return 0;462 463failure_finish_interrupt:464	pci402_finish_interrupt(pdev);465 466failure_finish_dma:467	pci402_finish_dma(pdev);468 469failure_unmap:470	pci_iounmap(pdev, card->addr);471 472failure_release_regions:473	pci_release_regions(pdev);474 475failure_disable_pci:476	pci_disable_device(pdev);477 478	return err;479}480 481static void pci402_remove(struct pci_dev *pdev)482{483	struct pci402_card *card = pci_get_drvdata(pdev);484 485	pci402_finish_interrupt(pdev);486	pci402_finish_cores(pdev);487	pci402_finish_dma(pdev);488	pci_iounmap(pdev, card->addr);489	pci_release_regions(pdev);490	pci_disable_device(pdev);491}492 493static const struct pci_device_id pci402_tbl[] = {494	{495		.vendor = PCI_VENDOR_ID_ESDGMBH,496		.device = ESD_PCI_DEVICE_ID_PCIE402,497		.subvendor = PCI_VENDOR_ID_ESDGMBH,498		.subdevice = PCI_ANY_ID,499	},500	{ 0, }501};502MODULE_DEVICE_TABLE(pci, pci402_tbl);503 504static struct pci_driver pci402_driver = {505	.name = KBUILD_MODNAME,506	.id_table = pci402_tbl,507	.probe = pci402_probe,508	.remove = pci402_remove,509};510module_pci_driver(pci402_driver);511 512MODULE_DESCRIPTION("Socket-CAN driver for esd CAN 402 card family with esdACC core on PCIe");513MODULE_AUTHOR("Thomas Körper <socketcan@esd.eu>");514MODULE_AUTHOR("Stefan Mätje <stefan.maetje@esd.eu>");515MODULE_LICENSE("GPL");516