devices/ccat/module-3.4-ethercat.c
branchstable-1.5
changeset 2550 7e25950ea941
parent 2549 933a1b36b05f
child 2551 000da5069f1a
equal deleted inserted replaced
2549:933a1b36b05f 2550:7e25950ea941
     1 ../../../ccat/module.c
     1 /**
       
     2     Network Driver for Beckhoff CCAT communication controller
       
     3     Copyright (C) 2014  Beckhoff Automation GmbH
       
     4     Author: Patrick Bruenn <p.bruenn@beckhoff.com>
       
     5 
       
     6     This program is free software; you can redistribute it and/or modify
       
     7     it under the terms of the GNU General Public License as published by
       
     8     the Free Software Foundation; either version 2 of the License, or
       
     9     (at your option) any later version.
       
    10 
       
    11     This program is distributed in the hope that it will be useful,
       
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14     GNU General Public License for more details.
       
    15 
       
    16     You should have received a copy of the GNU General Public License along
       
    17     with this program; if not, write to the Free Software Foundation, Inc.,
       
    18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
       
    19 */
       
    20 
       
    21 #include <asm/dma.h>
       
    22 #include <linux/etherdevice.h>
       
    23 #include <linux/module.h>
       
    24 #include <linux/netdevice.h>
       
    25 #include "module.h"
       
    26 #include "netdev.h"
       
    27 #include "update.h"
       
    28 
       
    29 MODULE_DESCRIPTION(DRV_DESCRIPTION);
       
    30 MODULE_AUTHOR("Patrick Bruenn <p.bruenn@beckhoff.com>");
       
    31 MODULE_LICENSE("GPL");
       
    32 MODULE_VERSION(DRV_VERSION);
       
    33 
       
    34 static void ccat_bar_free(struct ccat_bar *bar)
       
    35 {
       
    36 	if (bar->ioaddr) {
       
    37 		const struct ccat_bar tmp = *bar;
       
    38 		memset(bar, 0, sizeof(*bar));
       
    39 		iounmap(tmp.ioaddr);
       
    40 		release_mem_region(tmp.start, tmp.len);
       
    41 	} else {
       
    42 		pr_warn("%s(): %p was already done.\n", __FUNCTION__, bar);
       
    43 	}
       
    44 }
       
    45 
       
    46 /**
       
    47  * ccat_bar_init() - Initialize a CCAT pci bar
       
    48  * @bar object which should be initialized
       
    49  * @index 0 and 2 are valid for CCAT, meaning pci bar0 or pci bar2
       
    50  * @pdev the pci device as which the CCAT was recognized before
       
    51  *
       
    52  * Reading PCI config space; request and map memory region.
       
    53  */
       
    54 static int ccat_bar_init(struct ccat_bar *bar, size_t index,
       
    55 			 struct pci_dev *pdev)
       
    56 {
       
    57 	struct resource *res;
       
    58 	bar->start = pci_resource_start(pdev, index);
       
    59 	bar->end = pci_resource_end(pdev, index);
       
    60 	bar->len = pci_resource_len(pdev, index);
       
    61 	bar->flags = pci_resource_flags(pdev, index);
       
    62 	if (!(IORESOURCE_MEM & bar->flags)) {
       
    63 		pr_info("bar%llu is no mem_region -> abort.\n",
       
    64 			(uint64_t) index);
       
    65 		return -EIO;
       
    66 	}
       
    67 
       
    68 	res = request_mem_region(bar->start, bar->len, DRV_NAME);
       
    69 	if (!res) {
       
    70 		pr_info("allocate mem_region failed.\n");
       
    71 		return -EIO;
       
    72 	}
       
    73 	pr_debug("bar%llu at [%lx,%lx] len=%lu res: %p.\n", (uint64_t) index,
       
    74 		 bar->start, bar->end, bar->len, res);
       
    75 
       
    76 	bar->ioaddr = ioremap(bar->start, bar->len);
       
    77 	if (!bar->ioaddr) {
       
    78 		pr_info("bar%llu ioremap failed.\n", (uint64_t) index);
       
    79 		release_mem_region(bar->start, bar->len);
       
    80 		return -EIO;
       
    81 	}
       
    82 	pr_debug("bar%llu I/O mem mapped to %p.\n", (uint64_t) index,
       
    83 		 bar->ioaddr);
       
    84 	return 0;
       
    85 }
       
    86 
       
    87 void ccat_dma_free(struct ccat_dma *const dma)
       
    88 {
       
    89 	const struct ccat_dma tmp = *dma;
       
    90 	free_dma(dma->channel);
       
    91 	memset(dma, 0, sizeof(*dma));
       
    92 	dma_free_coherent(tmp.dev, tmp.size, tmp.virt, tmp.phys);
       
    93 }
       
    94 
       
    95 /**
       
    96  * ccat_dma_init() - Initialize CCAT and host memory for DMA transfer
       
    97  * @dma object for management data which will be initialized
       
    98  * @channel number of the DMA channel
       
    99  * @ioaddr of the pci bar2 configspace used to calculate the address of the pci dma configuration
       
   100  * @dev which should be configured for DMA
       
   101  */
       
   102 int ccat_dma_init(struct ccat_dma *const dma, size_t channel,
       
   103 		  void __iomem * const ioaddr, struct device *const dev)
       
   104 {
       
   105 	void *frame;
       
   106 	uint64_t addr;
       
   107 	uint32_t translateAddr;
       
   108 	uint32_t memTranslate;
       
   109 	uint32_t memSize;
       
   110 	uint32_t data = 0xffffffff;
       
   111 	uint32_t offset = (sizeof(uint64_t) * channel) + 0x1000;
       
   112 
       
   113 	dma->channel = channel;
       
   114 	dma->dev = dev;
       
   115 
       
   116 	/* calculate size and alignments */
       
   117 	iowrite32(data, ioaddr + offset);
       
   118 	wmb();
       
   119 	data = ioread32(ioaddr + offset);
       
   120 	memTranslate = data & 0xfffffffc;
       
   121 	memSize = (~memTranslate) + 1;
       
   122 	dma->size = 2 * memSize - PAGE_SIZE;
       
   123 	dma->virt = dma_zalloc_coherent(dev, dma->size, &dma->phys, GFP_KERNEL);
       
   124 	if (!dma->virt || !dma->phys) {
       
   125 		pr_info("init DMA%llu memory failed.\n", (uint64_t) channel);
       
   126 		return -1;
       
   127 	}
       
   128 
       
   129 	if (request_dma(channel, DRV_NAME)) {
       
   130 		pr_info("request dma channel %llu failed\n",
       
   131 			(uint64_t) channel);
       
   132 		ccat_dma_free(dma);
       
   133 		return -1;
       
   134 	}
       
   135 
       
   136 	translateAddr = (dma->phys + memSize - PAGE_SIZE) & memTranslate;
       
   137 	addr = translateAddr;
       
   138 	memcpy_toio(ioaddr + offset, &addr, sizeof(addr));
       
   139 	frame = dma->virt + translateAddr - dma->phys;
       
   140 	pr_debug
       
   141 	    ("DMA%llu mem initialized\n virt:         0x%p\n phys:         0x%llx\n translated:   0x%llx\n pci addr:     0x%08x%x\n memTranslate: 0x%x\n size:         %llu bytes.\n",
       
   142 	     (uint64_t) channel, dma->virt, (uint64_t) (dma->phys), addr,
       
   143 	     ioread32(ioaddr + offset + 4), ioread32(ioaddr + offset),
       
   144 	     memTranslate, (uint64_t) dma->size);
       
   145 	return 0;
       
   146 }
       
   147 
       
   148 /**
       
   149  * Initialize all available CCAT functions.
       
   150  *
       
   151  * Return: count of failed functions
       
   152  */
       
   153 static int ccat_functions_init(struct ccat_device *const ccatdev)
       
   154 {
       
   155 	/* read CCatInfoBlock.nMaxEntries from ccat */
       
   156 	const uint8_t num_func = ioread8(ccatdev->bar[0].ioaddr + 4);
       
   157 	void __iomem *addr = ccatdev->bar[0].ioaddr;
       
   158 	const void __iomem *end = addr + (sizeof(CCatInfoBlock) * num_func);
       
   159 	int status = 0;		//count init function failures
       
   160 
       
   161 	while (addr < end) {
       
   162 		const uint8_t type = ioread16(addr);
       
   163 		switch (type) {
       
   164 		case CCATINFO_NOTUSED:
       
   165 			break;
       
   166 		case CCATINFO_EPCS_PROM:
       
   167 			pr_info("Found: CCAT update(EPCS_PROM) -> init()\n");
       
   168 			ccatdev->update = ccat_update_init(ccatdev, addr);
       
   169 			status += (NULL == ccatdev->update);
       
   170 			break;
       
   171 		case CCATINFO_ETHERCAT_MASTER_DMA:
       
   172 			pr_info("Found: ETHERCAT_MASTER_DMA -> init()\n");
       
   173 			ccatdev->ethdev = ccat_eth_init(ccatdev, addr);
       
   174 			status += (NULL == ccatdev->ethdev);
       
   175 			break;
       
   176 		default:
       
   177 			pr_info("Found: 0x%04x not supported\n", type);
       
   178 			break;
       
   179 		}
       
   180 		addr += sizeof(CCatInfoBlock);
       
   181 	}
       
   182 	return status;
       
   183 }
       
   184 
       
   185 /**
       
   186  * Destroy all previously initialized CCAT functions
       
   187  */
       
   188 static void ccat_functions_remove(struct ccat_device *const ccatdev)
       
   189 {
       
   190 	if (!ccatdev->ethdev) {
       
   191 		pr_warn("%s(): 'ethdev' was not initialized.\n", __FUNCTION__);
       
   192 	} else {
       
   193 		struct ccat_eth_priv *const ethdev = ccatdev->ethdev;
       
   194 		ccatdev->ethdev = NULL;
       
   195 		ccat_eth_remove(ethdev);
       
   196 	}
       
   197 	if (!ccatdev->update) {
       
   198 		pr_warn("%s(): 'update' was not initialized.\n", __FUNCTION__);
       
   199 	} else {
       
   200 		struct ccat_update *const update = ccatdev->update;
       
   201 		ccatdev->update = NULL;
       
   202 		ccat_update_remove(update);
       
   203 	}
       
   204 }
       
   205 
       
   206 static int ccat_probe(struct pci_dev *pdev, const struct pci_device_id *id)
       
   207 {
       
   208 	int status;
       
   209 	u8 revision;
       
   210 	struct ccat_device *ccatdev = kmalloc(sizeof(*ccatdev), GFP_KERNEL);
       
   211 	if (!ccatdev) {
       
   212 		pr_err("%s() out of memory.\n", __FUNCTION__);
       
   213 		return -ENOMEM;
       
   214 	}
       
   215 	memset(ccatdev, 0, sizeof(*ccatdev));
       
   216 	ccatdev->pdev = pdev;
       
   217 	pci_set_drvdata(pdev, ccatdev);
       
   218 
       
   219 	status = pci_enable_device_mem(pdev);
       
   220 	if (status) {
       
   221 		pr_info("enable %s failed: %d\n", pdev->dev.kobj.name, status);
       
   222 		return status;
       
   223 	}
       
   224 
       
   225 	status = pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
       
   226 	if (status) {
       
   227 		pr_warn("read CCAT pci revision failed with %d\n", status);
       
   228 		return status;
       
   229 	}
       
   230 
       
   231 	/* FIXME upgrade to a newer kernel to get support of dma_set_mask_and_coherent()
       
   232 	 * (!dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(64))) {
       
   233 	 */
       
   234 	if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
       
   235 		pr_debug("64 bit DMA supported, pci rev: %u\n", revision);
       
   236 		/*} else if (!dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) { */
       
   237 	} else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
       
   238 		pr_debug("32 bit DMA supported, pci rev: %u\n", revision);
       
   239 	} else {
       
   240 		pr_warn("No suitable DMA available, pci rev: %u\n", revision);
       
   241 	}
       
   242 
       
   243 	if (ccat_bar_init(&ccatdev->bar[0], 0, pdev)) {
       
   244 		pr_warn("initialization of bar0 failed.\n");
       
   245 		return -EIO;
       
   246 	}
       
   247 
       
   248 	if (ccat_bar_init(&ccatdev->bar[2], 2, pdev)) {
       
   249 		pr_warn("initialization of bar2 failed.\n");
       
   250 		return -EIO;
       
   251 	}
       
   252 
       
   253 	pci_set_master(pdev);
       
   254 	if (ccat_functions_init(ccatdev)) {
       
   255 		pr_warn("some functions couldn't be initialized\n");
       
   256 	}
       
   257 	return 0;
       
   258 }
       
   259 
       
   260 static void ccat_remove(struct pci_dev *pdev)
       
   261 {
       
   262 	struct ccat_device *ccatdev = pci_get_drvdata(pdev);
       
   263 	if (ccatdev) {
       
   264 		ccat_functions_remove(ccatdev);
       
   265 		ccat_bar_free(&ccatdev->bar[2]);
       
   266 		ccat_bar_free(&ccatdev->bar[0]);
       
   267 		pci_disable_device(pdev);
       
   268 		pci_set_drvdata(pdev, NULL);
       
   269 		kfree(ccatdev);
       
   270 	}
       
   271 	pr_debug("%s() done.\n", __FUNCTION__);
       
   272 }
       
   273 
       
   274 #define PCI_DEVICE_ID_BECKHOFF_CCAT 0x5000
       
   275 #define PCI_VENDOR_ID_BECKHOFF 0x15EC
       
   276 
       
   277 static const struct pci_device_id pci_ids[] = {
       
   278 	{PCI_DEVICE(PCI_VENDOR_ID_BECKHOFF, PCI_DEVICE_ID_BECKHOFF_CCAT)},
       
   279 	{0,},
       
   280 };
       
   281 
       
   282 MODULE_DEVICE_TABLE(pci, pci_ids);
       
   283 
       
   284 static struct pci_driver pci_driver = {
       
   285 	.name = DRV_NAME,
       
   286 	.id_table = pci_ids,
       
   287 	.probe = ccat_probe,
       
   288 	.remove = ccat_remove,
       
   289 };
       
   290 
       
   291 static void ccat_exit_module(void)
       
   292 {
       
   293 	pci_unregister_driver(&pci_driver);
       
   294 }
       
   295 
       
   296 static int ccat_init_module(void)
       
   297 {
       
   298 	static const size_t offset = offsetof(struct ccat_eth_frame, data);
       
   299 	BUILD_BUG_ON(sizeof(struct ccat_eth_frame) != sizeof(CCatDmaTxFrame));
       
   300 	BUILD_BUG_ON(sizeof(struct ccat_eth_frame) != sizeof(CCatRxDesc));
       
   301 	BUILD_BUG_ON(offset != offsetof(CCatDmaTxFrame, data));
       
   302 	BUILD_BUG_ON(offset != offsetof(CCatRxDesc, data));
       
   303 	pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
       
   304 	return pci_register_driver(&pci_driver);
       
   305 }
       
   306 
       
   307 module_exit(ccat_exit_module);
       
   308 module_init(ccat_init_module);