nosy.c revision 55e77c06c6017a70630cf599770369b8ba07c841
1/* 2 * nosy - Snoop mode driver for TI PCILynx 1394 controllers 3 * Copyright (C) 2002-2007 Kristian Høgsberg 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software Foundation, 17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20#include <linux/errno.h> 21#include <linux/fs.h> 22#include <linux/init.h> 23#include <linux/interrupt.h> 24#include <linux/io.h> 25#include <linux/kernel.h> 26#include <linux/miscdevice.h> 27#include <linux/module.h> 28#include <linux/pci.h> 29#include <linux/poll.h> 30#include <linux/sched.h> /* required for linux/wait.h */ 31#include <linux/slab.h> 32#include <linux/spinlock.h> 33#include <linux/timex.h> 34#include <linux/uaccess.h> 35#include <linux/wait.h> 36 37#include <asm/atomic.h> 38#include <asm/byteorder.h> 39 40#include "nosy.h" 41#include "nosy-user.h" 42 43#define TCODE_PHY_PACKET 0x10 44#define PCI_DEVICE_ID_TI_PCILYNX 0x8000 45 46#define notify(s, args...) printk(KERN_NOTICE s, ## args) 47#define error(s, args...) printk(KERN_ERR s, ## args) 48#define debug(s, args...) printk(KERN_DEBUG s, ## args) 49 50static char driver_name[] = KBUILD_MODNAME; 51 52struct pcl_status { 53 unsigned int transfer_count : 13; 54 unsigned int reserved0 : 1; 55 unsigned int ack_type : 1; 56 unsigned int ack : 4; 57 unsigned int rcv_speed : 2; 58 unsigned int rcv_dma_channel : 6; 59 unsigned int packet_complete : 1; 60 unsigned int packet_error : 1; 61 unsigned int master_error : 1; 62 unsigned int iso_mode : 1; 63 unsigned int self_id : 1; 64}; 65 66/* this is the physical layout of a PCL, its size is 128 bytes */ 67struct pcl { 68 u32 next; 69 u32 async_error_next; 70 u32 user_data; 71 struct pcl_status pcl_status; 72 u32 remaining_transfer_count; 73 u32 next_data_buffer; 74 struct { 75 u32 control; 76 u32 pointer; 77 } buffer[13] __attribute__ ((packed)); 78} __attribute__ ((packed)); 79 80struct packet { 81 unsigned int length; 82 char data[0]; 83}; 84 85struct packet_buffer { 86 char *data; 87 size_t capacity; 88 long total_packet_count, lost_packet_count; 89 atomic_t size; 90 struct packet *head, *tail; 91 wait_queue_head_t wait; 92}; 93 94struct pcilynx { 95 struct pci_dev *pci_device; 96 unsigned char *registers; 97 98 struct pcl *rcv_start_pcl, *rcv_pcl; 99 u32 *rcv_buffer; 100 101 dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 102 103 spinlock_t client_list_lock; 104 struct list_head client_list; 105 106 struct miscdevice misc; 107}; 108 109struct client { 110 struct pcilynx *lynx; 111 u32 tcode_mask; 112 struct packet_buffer buffer; 113 struct list_head link; 114}; 115 116#define MAX_MINORS 64 117static struct pcilynx *minors[MAX_MINORS]; 118 119static int 120packet_buffer_init(struct packet_buffer *buffer, size_t capacity) 121{ 122 buffer->data = kmalloc(capacity, GFP_KERNEL); 123 if (buffer->data == NULL) 124 return -ENOMEM; 125 buffer->head = (struct packet *) buffer->data; 126 buffer->tail = (struct packet *) buffer->data; 127 buffer->capacity = capacity; 128 buffer->lost_packet_count = 0; 129 atomic_set(&buffer->size, 0); 130 init_waitqueue_head(&buffer->wait); 131 132 return 0; 133} 134 135static void 136packet_buffer_destroy(struct packet_buffer *buffer) 137{ 138 kfree(buffer->data); 139} 140 141static int 142packet_buffer_get(struct packet_buffer *buffer, void *data, size_t user_length) 143{ 144 size_t length; 145 char *end; 146 147 if (wait_event_interruptible(buffer->wait, 148 atomic_read(&buffer->size) > 0)) 149 return -ERESTARTSYS; 150 151 /* FIXME: Check length <= user_length. */ 152 153 end = buffer->data + buffer->capacity; 154 length = buffer->head->length; 155 156 if (&buffer->head->data[length] < end) { 157 if (copy_to_user(data, buffer->head->data, length)) 158 return -EFAULT; 159 buffer->head = (struct packet *) &buffer->head->data[length]; 160 } else { 161 size_t split = end - buffer->head->data; 162 163 if (copy_to_user(data, buffer->head->data, split)) 164 return -EFAULT; 165 if (copy_to_user(data + split, buffer->data, length - split)) 166 return -EFAULT; 167 buffer->head = (struct packet *) &buffer->data[length - split]; 168 } 169 170 /* 171 * Decrease buffer->size as the last thing, since this is what 172 * keeps the interrupt from overwriting the packet we are 173 * retrieving from the buffer. 174 */ 175 atomic_sub(sizeof(struct packet) + length, &buffer->size); 176 177 return length; 178} 179 180static void 181packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) 182{ 183 char *end; 184 185 buffer->total_packet_count++; 186 187 if (buffer->capacity < 188 atomic_read(&buffer->size) + sizeof(struct packet) + length) { 189 buffer->lost_packet_count++; 190 return; 191 } 192 193 end = buffer->data + buffer->capacity; 194 buffer->tail->length = length; 195 196 if (&buffer->tail->data[length] < end) { 197 memcpy(buffer->tail->data, data, length); 198 buffer->tail = (struct packet *) &buffer->tail->data[length]; 199 } else { 200 size_t split = end - buffer->tail->data; 201 202 memcpy(buffer->tail->data, data, split); 203 memcpy(buffer->data, data + split, length - split); 204 buffer->tail = (struct packet *) &buffer->data[length - split]; 205 } 206 207 /* Finally, adjust buffer size and wake up userspace reader. */ 208 209 atomic_add(sizeof(struct packet) + length, &buffer->size); 210 wake_up_interruptible(&buffer->wait); 211} 212 213static inline void 214reg_write(struct pcilynx *lynx, int offset, u32 data) 215{ 216 writel(data, lynx->registers + offset); 217} 218 219static inline u32 220reg_read(struct pcilynx *lynx, int offset) 221{ 222 return readl(lynx->registers + offset); 223} 224 225static inline void 226reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) 227{ 228 reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); 229} 230 231/* 232 * Maybe the pcl programs could be set up to just append data instead 233 * of using a whole packet. 234 */ 235static inline void 236run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, 237 int dmachan) 238{ 239 reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); 240 reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, 241 DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); 242} 243 244static int 245set_phy_reg(struct pcilynx *lynx, int addr, int val) 246{ 247 if (addr > 15) { 248 debug("PHY register address %d out of range\n", addr); 249 return -1; 250 } 251 252 if (val > 0xff) { 253 debug("PHY register value %d out of range\n", val); 254 return -1; 255 } 256 257 reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | 258 LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); 259 260 return 0; 261} 262 263static int 264nosy_open(struct inode *inode, struct file *file) 265{ 266 int minor = iminor(inode); 267 struct client *client; 268 269 if (minor > MAX_MINORS || minors[minor] == NULL) 270 return -ENODEV; 271 272 client = kmalloc(sizeof *client, GFP_KERNEL); 273 if (client == NULL) 274 return -ENOMEM; 275 276 client->tcode_mask = ~0; 277 client->lynx = minors[minor]; 278 INIT_LIST_HEAD(&client->link); 279 280 if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) { 281 kfree(client); 282 return -ENOMEM; 283 } 284 285 file->private_data = client; 286 287 return 0; 288} 289 290static int 291nosy_release(struct inode *inode, struct file *file) 292{ 293 struct client *client = file->private_data; 294 295 spin_lock_irq(&client->lynx->client_list_lock); 296 list_del_init(&client->link); 297 spin_unlock_irq(&client->lynx->client_list_lock); 298 299 packet_buffer_destroy(&client->buffer); 300 kfree(client); 301 302 return 0; 303} 304 305static unsigned int 306nosy_poll(struct file *file, poll_table *pt) 307{ 308 struct client *client = file->private_data; 309 310 poll_wait(file, &client->buffer.wait, pt); 311 312 if (atomic_read(&client->buffer.size) > 0) 313 return POLLIN | POLLRDNORM; 314 else 315 return 0; 316} 317 318static ssize_t 319nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset) 320{ 321 struct client *client = file->private_data; 322 323 return packet_buffer_get(&client->buffer, buffer, count); 324} 325 326static long 327nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 328{ 329 struct client *client = file->private_data; 330 spinlock_t *client_list_lock = &client->lynx->client_list_lock; 331 struct nosy_stats stats; 332 333 switch (cmd) { 334 case NOSY_IOC_GET_STATS: 335 spin_lock_irq(client_list_lock); 336 stats.total_packet_count = client->buffer.total_packet_count; 337 stats.lost_packet_count = client->buffer.lost_packet_count; 338 spin_unlock_irq(client_list_lock); 339 340 if (copy_to_user((void *) arg, &stats, sizeof stats)) 341 return -EFAULT; 342 else 343 return 0; 344 345 case NOSY_IOC_START: 346 spin_lock_irq(client_list_lock); 347 list_add_tail(&client->link, &client->lynx->client_list); 348 spin_unlock_irq(client_list_lock); 349 350 return 0; 351 352 case NOSY_IOC_STOP: 353 spin_lock_irq(client_list_lock); 354 list_del_init(&client->link); 355 spin_unlock_irq(client_list_lock); 356 357 return 0; 358 359 case NOSY_IOC_FILTER: 360 spin_lock_irq(client_list_lock); 361 client->tcode_mask = arg; 362 spin_unlock_irq(client_list_lock); 363 364 return 0; 365 366 default: 367 return -EINVAL; 368 /* Flush buffer, configure filter. */ 369 } 370} 371 372static const struct file_operations nosy_ops = { 373 .owner = THIS_MODULE, 374 .read = nosy_read, 375 .unlocked_ioctl = nosy_ioctl, 376 .poll = nosy_poll, 377 .open = nosy_open, 378 .release = nosy_release, 379}; 380 381#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 382 383struct link_packet { 384 unsigned int priority : 4; 385 unsigned int tcode : 4; 386 unsigned int rt : 2; 387 unsigned int tlabel : 6; 388 unsigned int destination : 16; 389}; 390 391static void 392packet_irq_handler(struct pcilynx *lynx) 393{ 394 struct client *client; 395 u32 tcode_mask; 396 size_t length; 397 struct link_packet *packet; 398 struct timeval tv; 399 400 /* FIXME: Also report rcv_speed. */ 401 402 length = lynx->rcv_pcl->pcl_status.transfer_count; 403 packet = (struct link_packet *) &lynx->rcv_buffer[1]; 404 405 do_gettimeofday(&tv); 406 lynx->rcv_buffer[0] = tv.tv_usec; 407 408 if (length == PHY_PACKET_SIZE) 409 tcode_mask = 1 << TCODE_PHY_PACKET; 410 else 411 tcode_mask = 1 << packet->tcode; 412 413 spin_lock(&lynx->client_list_lock); 414 415 list_for_each_entry(client, &lynx->client_list, link) 416 if (client->tcode_mask & tcode_mask) 417 packet_buffer_put(&client->buffer, 418 lynx->rcv_buffer, length + 4); 419 420 spin_unlock(&lynx->client_list_lock); 421} 422 423static void 424bus_reset_irq_handler(struct pcilynx *lynx) 425{ 426 struct client *client; 427 struct timeval tv; 428 429 do_gettimeofday(&tv); 430 431 spin_lock(&lynx->client_list_lock); 432 433 list_for_each_entry(client, &lynx->client_list, link) 434 packet_buffer_put(&client->buffer, &tv.tv_usec, 4); 435 436 spin_unlock(&lynx->client_list_lock); 437} 438 439static irqreturn_t 440irq_handler(int irq, void *device) 441{ 442 struct pcilynx *lynx = device; 443 u32 pci_int_status; 444 445 pci_int_status = reg_read(lynx, PCI_INT_STATUS); 446 447 if ((pci_int_status & PCI_INT_INT_PEND) == 0) 448 /* Not our interrupt, bail out quickly. */ 449 return IRQ_NONE; 450 451 if ((pci_int_status & PCI_INT_P1394_INT) != 0) { 452 u32 link_int_status; 453 454 link_int_status = reg_read(lynx, LINK_INT_STATUS); 455 reg_write(lynx, LINK_INT_STATUS, link_int_status); 456 457 if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) 458 bus_reset_irq_handler(lynx); 459 } 460 461 /* Clear the PCI_INT_STATUS register only after clearing the 462 * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will 463 * be set again immediately. */ 464 465 reg_write(lynx, PCI_INT_STATUS, pci_int_status); 466 467 if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { 468 packet_irq_handler(lynx); 469 run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 470 } 471 472 return IRQ_HANDLED; 473} 474 475static void 476remove_card(struct pci_dev *dev) 477{ 478 struct pcilynx *lynx; 479 480 lynx = pci_get_drvdata(dev); 481 if (!lynx) 482 return; 483 pci_set_drvdata(dev, NULL); 484 485 reg_write(lynx, PCI_INT_ENABLE, 0); 486 free_irq(lynx->pci_device->irq, lynx); 487 488 pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 489 lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 490 pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 491 lynx->rcv_pcl, lynx->rcv_pcl_bus); 492 pci_free_consistent(lynx->pci_device, PAGE_SIZE, 493 lynx->rcv_buffer, lynx->rcv_buffer_bus); 494 495 iounmap(lynx->registers); 496 497 minors[lynx->misc.minor] = NULL; 498 misc_deregister(&lynx->misc); 499 500 kfree(lynx); 501} 502 503#define RCV_BUFFER_SIZE (16 * 1024) 504 505static int __devinit 506add_card(struct pci_dev *dev, const struct pci_device_id *unused) 507{ 508 struct pcilynx *lynx; 509 u32 p, end; 510 int i; 511 512 if (pci_set_dma_mask(dev, 0xffffffff)) { 513 error("DMA address limits not supported " 514 "for PCILynx hardware\n"); 515 return -ENXIO; 516 } 517 if (pci_enable_device(dev)) { 518 error("Failed to enable PCILynx hardware\n"); 519 return -ENXIO; 520 } 521 pci_set_master(dev); 522 523 lynx = kzalloc(sizeof *lynx, GFP_KERNEL); 524 if (lynx == NULL) { 525 error("Failed to allocate control structure memory\n"); 526 return -ENOMEM; 527 } 528 lynx->pci_device = dev; 529 pci_set_drvdata(dev, lynx); 530 531 spin_lock_init(&lynx->client_list_lock); 532 INIT_LIST_HEAD(&lynx->client_list); 533 534 lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), 535 PCILYNX_MAX_REGISTER); 536 537 lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, 538 sizeof(struct pcl), &lynx->rcv_start_pcl_bus); 539 lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, 540 sizeof(struct pcl), &lynx->rcv_pcl_bus); 541 lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, 542 RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); 543 if (lynx->rcv_start_pcl == NULL || 544 lynx->rcv_pcl == NULL || 545 lynx->rcv_buffer == NULL) { 546 /* FIXME: do proper error handling. */ 547 error("Failed to allocate receive buffer\n"); 548 return -ENOMEM; 549 } 550 lynx->rcv_start_pcl->next = lynx->rcv_pcl_bus; 551 lynx->rcv_pcl->next = PCL_NEXT_INVALID; 552 lynx->rcv_pcl->async_error_next = PCL_NEXT_INVALID; 553 554 lynx->rcv_pcl->buffer[0].control = 555 PCL_CMD_RCV | PCL_BIGENDIAN | 2044; 556 lynx->rcv_pcl->buffer[0].pointer = lynx->rcv_buffer_bus + 4; 557 p = lynx->rcv_buffer_bus + 2048; 558 end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 559 for (i = 1; p < end; i++, p += 2048) { 560 lynx->rcv_pcl->buffer[i].control = 561 PCL_CMD_RCV | PCL_BIGENDIAN | 2048; 562 lynx->rcv_pcl->buffer[i].pointer = p; 563 } 564 lynx->rcv_pcl->buffer[i - 1].control |= PCL_LAST_BUFF; 565 566 reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 567 /* Fix buggy cards with autoboot pin not tied low: */ 568 reg_write(lynx, DMA0_CHAN_CTRL, 0); 569 reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); 570 571#if 0 572 /* now, looking for PHY register set */ 573 if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { 574 lynx->phyic.reg_1394a = 1; 575 PRINT(KERN_INFO, lynx->id, 576 "found 1394a conform PHY (using extended register set)"); 577 lynx->phyic.vendor = get_phy_vendorid(lynx); 578 lynx->phyic.product = get_phy_productid(lynx); 579 } else { 580 lynx->phyic.reg_1394a = 0; 581 PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); 582 } 583#endif 584 585 /* Setup the general receive FIFO max size. */ 586 reg_write(lynx, FIFO_SIZES, 255); 587 588 reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); 589 590 reg_write(lynx, LINK_INT_ENABLE, 591 LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | 592 LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | 593 LINK_INT_AT_STUCK | LINK_INT_SNTRJ | 594 LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | 595 LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); 596 597 /* Disable the L flag in self ID packets. */ 598 set_phy_reg(lynx, 4, 0); 599 600 /* Put this baby into snoop mode */ 601 reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); 602 603 run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 604 605 if (request_irq(dev->irq, irq_handler, IRQF_SHARED, 606 driver_name, lynx)) { 607 error("Failed to allocate shared interrupt %d\n", dev->irq); 608 return -EIO; 609 } 610 611 lynx->misc.parent = &dev->dev; 612 lynx->misc.minor = MISC_DYNAMIC_MINOR; 613 lynx->misc.name = "nosy"; 614 lynx->misc.fops = &nosy_ops; 615 if (misc_register(&lynx->misc)) { 616 error("Failed to register misc char device\n"); 617 return -ENOMEM; 618 } 619 minors[lynx->misc.minor] = lynx; 620 621 notify("Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); 622 623 return 0; 624} 625 626static struct pci_device_id pci_table[] __devinitdata = { 627 { 628 .vendor = PCI_VENDOR_ID_TI, 629 .device = PCI_DEVICE_ID_TI_PCILYNX, 630 .subvendor = PCI_ANY_ID, 631 .subdevice = PCI_ANY_ID, 632 }, 633 { } /* Terminating entry */ 634}; 635 636static struct pci_driver lynx_pci_driver = { 637 .name = driver_name, 638 .id_table = pci_table, 639 .probe = add_card, 640 .remove = remove_card, 641}; 642 643MODULE_AUTHOR("Kristian Hoegsberg"); 644MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); 645MODULE_LICENSE("GPL"); 646MODULE_DEVICE_TABLE(pci, pci_table); 647 648static int __init nosy_init(void) 649{ 650 return pci_register_driver(&lynx_pci_driver); 651} 652 653static void __exit nosy_cleanup(void) 654{ 655 pci_unregister_driver(&lynx_pci_driver); 656 657 notify("Unloaded %s.\n", driver_name); 658} 659 660module_init(nosy_init); 661module_exit(nosy_cleanup); 662