1b5e47729SStefan Richter /* 2b5e47729SStefan Richter * nosy - Snoop mode driver for TI PCILynx 1394 controllers 3b5e47729SStefan Richter * Copyright (C) 2002-2007 Kristian Høgsberg 428646821SStefan Richter * 528646821SStefan Richter * This program is free software; you can redistribute it and/or modify 628646821SStefan Richter * it under the terms of the GNU General Public License as published by 728646821SStefan Richter * the Free Software Foundation; either version 2 of the License, or 828646821SStefan Richter * (at your option) any later version. 928646821SStefan Richter * 1028646821SStefan Richter * This program is distributed in the hope that it will be useful, 1128646821SStefan Richter * but WITHOUT ANY WARRANTY; without even the implied warranty of 1228646821SStefan Richter * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1328646821SStefan Richter * GNU General Public License for more details. 1428646821SStefan Richter * 1528646821SStefan Richter * You should have received a copy of the GNU General Public License 1628646821SStefan Richter * along with this program; if not, write to the Free Software Foundation, 1728646821SStefan Richter * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1828646821SStefan Richter */ 1928646821SStefan Richter 207429b17dSStefan Richter #include <linux/device.h> 2128646821SStefan Richter #include <linux/errno.h> 2228646821SStefan Richter #include <linux/fs.h> 23b5e47729SStefan Richter #include <linux/init.h> 24b5e47729SStefan Richter #include <linux/interrupt.h> 25b5e47729SStefan Richter #include <linux/io.h> 26b5e47729SStefan Richter #include <linux/kernel.h> 27424d66ceSStefan Richter #include <linux/kref.h> 2828646821SStefan Richter #include <linux/miscdevice.h> 29b5e47729SStefan Richter #include <linux/module.h> 30424d66ceSStefan Richter #include <linux/mutex.h> 31b5e47729SStefan Richter #include <linux/pci.h> 32b5e47729SStefan Richter #include <linux/poll.h> 33b5e47729SStefan Richter #include <linux/sched.h> /* required for linux/wait.h */ 34b5e47729SStefan Richter #include <linux/slab.h> 35b5e47729SStefan Richter #include <linux/spinlock.h> 362ae4b6b2SAmitoj Kaur Chawla #include <linux/time64.h> 37b5e47729SStefan Richter #include <linux/timex.h> 38b5e47729SStefan Richter #include <linux/uaccess.h> 39b5e47729SStefan Richter #include <linux/wait.h> 40e894d1d7Ssantosh nayak #include <linux/dma-mapping.h> 4160063497SArun Sharma #include <linux/atomic.h> 42b5e47729SStefan Richter #include <asm/byteorder.h> 4328646821SStefan Richter 4428646821SStefan Richter #include "nosy.h" 4528646821SStefan Richter #include "nosy-user.h" 4628646821SStefan Richter 4728646821SStefan Richter #define TCODE_PHY_PACKET 0x10 4828646821SStefan Richter #define PCI_DEVICE_ID_TI_PCILYNX 0x8000 4928646821SStefan Richter 50b5e47729SStefan Richter static char driver_name[] = KBUILD_MODNAME; 5128646821SStefan Richter 5228646821SStefan Richter /* this is the physical layout of a PCL, its size is 128 bytes */ 5328646821SStefan Richter struct pcl { 54fd8c8d46SStefan Richter __le32 next; 55fd8c8d46SStefan Richter __le32 async_error_next; 5628646821SStefan Richter u32 user_data; 57fd8c8d46SStefan Richter __le32 pcl_status; 58fd8c8d46SStefan Richter __le32 remaining_transfer_count; 59fd8c8d46SStefan Richter __le32 next_data_buffer; 6028646821SStefan Richter struct { 61fd8c8d46SStefan Richter __le32 control; 62fd8c8d46SStefan Richter __le32 pointer; 63fd8c8d46SStefan Richter } buffer[13]; 64fd8c8d46SStefan Richter }; 6528646821SStefan Richter 6628646821SStefan Richter struct packet { 67b5e47729SStefan Richter unsigned int length; 6828646821SStefan Richter char data[0]; 6928646821SStefan Richter }; 7028646821SStefan Richter 7128646821SStefan Richter struct packet_buffer { 7228646821SStefan Richter char *data; 7328646821SStefan Richter size_t capacity; 7428646821SStefan Richter long total_packet_count, lost_packet_count; 7528646821SStefan Richter atomic_t size; 7628646821SStefan Richter struct packet *head, *tail; 7728646821SStefan Richter wait_queue_head_t wait; 7828646821SStefan Richter }; 7928646821SStefan Richter 8028646821SStefan Richter struct pcilynx { 8128646821SStefan Richter struct pci_dev *pci_device; 82c89db7b8SStefan Richter __iomem char *registers; 8328646821SStefan Richter 8428646821SStefan Richter struct pcl *rcv_start_pcl, *rcv_pcl; 85fd8c8d46SStefan Richter __le32 *rcv_buffer; 8628646821SStefan Richter 8728646821SStefan Richter dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 8828646821SStefan Richter 8928646821SStefan Richter spinlock_t client_list_lock; 9028646821SStefan Richter struct list_head client_list; 9128646821SStefan Richter 9228646821SStefan Richter struct miscdevice misc; 93424d66ceSStefan Richter struct list_head link; 94424d66ceSStefan Richter struct kref kref; 9528646821SStefan Richter }; 9628646821SStefan Richter 97424d66ceSStefan Richter static inline struct pcilynx * 98424d66ceSStefan Richter lynx_get(struct pcilynx *lynx) 99424d66ceSStefan Richter { 100424d66ceSStefan Richter kref_get(&lynx->kref); 101424d66ceSStefan Richter 102424d66ceSStefan Richter return lynx; 103424d66ceSStefan Richter } 104424d66ceSStefan Richter 105424d66ceSStefan Richter static void 106424d66ceSStefan Richter lynx_release(struct kref *kref) 107424d66ceSStefan Richter { 108424d66ceSStefan Richter kfree(container_of(kref, struct pcilynx, kref)); 109424d66ceSStefan Richter } 110424d66ceSStefan Richter 111424d66ceSStefan Richter static inline void 112424d66ceSStefan Richter lynx_put(struct pcilynx *lynx) 113424d66ceSStefan Richter { 114424d66ceSStefan Richter kref_put(&lynx->kref, lynx_release); 115424d66ceSStefan Richter } 116424d66ceSStefan Richter 11728646821SStefan Richter struct client { 11828646821SStefan Richter struct pcilynx *lynx; 119c7b2a99cSStefan Richter u32 tcode_mask; 12028646821SStefan Richter struct packet_buffer buffer; 12128646821SStefan Richter struct list_head link; 12228646821SStefan Richter }; 12328646821SStefan Richter 124424d66ceSStefan Richter static DEFINE_MUTEX(card_mutex); 125424d66ceSStefan Richter static LIST_HEAD(card_list); 12628646821SStefan Richter 12728646821SStefan Richter static int 12828646821SStefan Richter packet_buffer_init(struct packet_buffer *buffer, size_t capacity) 12928646821SStefan Richter { 13028646821SStefan Richter buffer->data = kmalloc(capacity, GFP_KERNEL); 13128646821SStefan Richter if (buffer->data == NULL) 13228646821SStefan Richter return -ENOMEM; 13328646821SStefan Richter buffer->head = (struct packet *) buffer->data; 13428646821SStefan Richter buffer->tail = (struct packet *) buffer->data; 13528646821SStefan Richter buffer->capacity = capacity; 13628646821SStefan Richter buffer->lost_packet_count = 0; 13728646821SStefan Richter atomic_set(&buffer->size, 0); 13828646821SStefan Richter init_waitqueue_head(&buffer->wait); 13928646821SStefan Richter 14028646821SStefan Richter return 0; 14128646821SStefan Richter } 14228646821SStefan Richter 14328646821SStefan Richter static void 14428646821SStefan Richter packet_buffer_destroy(struct packet_buffer *buffer) 14528646821SStefan Richter { 14628646821SStefan Richter kfree(buffer->data); 14728646821SStefan Richter } 14828646821SStefan Richter 14928646821SStefan Richter static int 150c89db7b8SStefan Richter packet_buffer_get(struct client *client, char __user *data, size_t user_length) 15128646821SStefan Richter { 152424d66ceSStefan Richter struct packet_buffer *buffer = &client->buffer; 15328646821SStefan Richter size_t length; 15428646821SStefan Richter char *end; 15528646821SStefan Richter 15628646821SStefan Richter if (wait_event_interruptible(buffer->wait, 157424d66ceSStefan Richter atomic_read(&buffer->size) > 0) || 158424d66ceSStefan Richter list_empty(&client->lynx->link)) 15928646821SStefan Richter return -ERESTARTSYS; 16028646821SStefan Richter 161424d66ceSStefan Richter if (atomic_read(&buffer->size) == 0) 162424d66ceSStefan Richter return -ENODEV; 163424d66ceSStefan Richter 16428646821SStefan Richter /* FIXME: Check length <= user_length. */ 16528646821SStefan Richter 16628646821SStefan Richter end = buffer->data + buffer->capacity; 16728646821SStefan Richter length = buffer->head->length; 16828646821SStefan Richter 16928646821SStefan Richter if (&buffer->head->data[length] < end) { 17028646821SStefan Richter if (copy_to_user(data, buffer->head->data, length)) 17128646821SStefan Richter return -EFAULT; 17228646821SStefan Richter buffer->head = (struct packet *) &buffer->head->data[length]; 173b5e47729SStefan Richter } else { 17428646821SStefan Richter size_t split = end - buffer->head->data; 17528646821SStefan Richter 17628646821SStefan Richter if (copy_to_user(data, buffer->head->data, split)) 17728646821SStefan Richter return -EFAULT; 17828646821SStefan Richter if (copy_to_user(data + split, buffer->data, length - split)) 17928646821SStefan Richter return -EFAULT; 18028646821SStefan Richter buffer->head = (struct packet *) &buffer->data[length - split]; 18128646821SStefan Richter } 18228646821SStefan Richter 183b5e47729SStefan Richter /* 184b5e47729SStefan Richter * Decrease buffer->size as the last thing, since this is what 18528646821SStefan Richter * keeps the interrupt from overwriting the packet we are 186b5e47729SStefan Richter * retrieving from the buffer. 187b5e47729SStefan Richter */ 18828646821SStefan Richter atomic_sub(sizeof(struct packet) + length, &buffer->size); 18928646821SStefan Richter 19028646821SStefan Richter return length; 19128646821SStefan Richter } 19228646821SStefan Richter 19328646821SStefan Richter static void 19428646821SStefan Richter packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) 19528646821SStefan Richter { 19628646821SStefan Richter char *end; 19728646821SStefan Richter 19828646821SStefan Richter buffer->total_packet_count++; 19928646821SStefan Richter 20028646821SStefan Richter if (buffer->capacity < 20128646821SStefan Richter atomic_read(&buffer->size) + sizeof(struct packet) + length) { 20228646821SStefan Richter buffer->lost_packet_count++; 20328646821SStefan Richter return; 20428646821SStefan Richter } 20528646821SStefan Richter 20628646821SStefan Richter end = buffer->data + buffer->capacity; 20728646821SStefan Richter buffer->tail->length = length; 20828646821SStefan Richter 20928646821SStefan Richter if (&buffer->tail->data[length] < end) { 21028646821SStefan Richter memcpy(buffer->tail->data, data, length); 21128646821SStefan Richter buffer->tail = (struct packet *) &buffer->tail->data[length]; 212b5e47729SStefan Richter } else { 21328646821SStefan Richter size_t split = end - buffer->tail->data; 21428646821SStefan Richter 21528646821SStefan Richter memcpy(buffer->tail->data, data, split); 21628646821SStefan Richter memcpy(buffer->data, data + split, length - split); 21728646821SStefan Richter buffer->tail = (struct packet *) &buffer->data[length - split]; 21828646821SStefan Richter } 21928646821SStefan Richter 22028646821SStefan Richter /* Finally, adjust buffer size and wake up userspace reader. */ 22128646821SStefan Richter 22228646821SStefan Richter atomic_add(sizeof(struct packet) + length, &buffer->size); 22328646821SStefan Richter wake_up_interruptible(&buffer->wait); 22428646821SStefan Richter } 22528646821SStefan Richter 22628646821SStefan Richter static inline void 22728646821SStefan Richter reg_write(struct pcilynx *lynx, int offset, u32 data) 22828646821SStefan Richter { 22928646821SStefan Richter writel(data, lynx->registers + offset); 23028646821SStefan Richter } 23128646821SStefan Richter 23228646821SStefan Richter static inline u32 23328646821SStefan Richter reg_read(struct pcilynx *lynx, int offset) 23428646821SStefan Richter { 23528646821SStefan Richter return readl(lynx->registers + offset); 23628646821SStefan Richter } 23728646821SStefan Richter 23828646821SStefan Richter static inline void 23928646821SStefan Richter reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) 24028646821SStefan Richter { 24128646821SStefan Richter reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); 24228646821SStefan Richter } 24328646821SStefan Richter 244b5e47729SStefan Richter /* 245b5e47729SStefan Richter * Maybe the pcl programs could be set up to just append data instead 246b5e47729SStefan Richter * of using a whole packet. 247b5e47729SStefan Richter */ 24828646821SStefan Richter static inline void 249b5e47729SStefan Richter run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, 250b5e47729SStefan Richter int dmachan) 25128646821SStefan Richter { 25228646821SStefan Richter reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); 25328646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, 25428646821SStefan Richter DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); 25528646821SStefan Richter } 25628646821SStefan Richter 25728646821SStefan Richter static int 25828646821SStefan Richter set_phy_reg(struct pcilynx *lynx, int addr, int val) 25928646821SStefan Richter { 26028646821SStefan Richter if (addr > 15) { 2617429b17dSStefan Richter dev_err(&lynx->pci_device->dev, 2627429b17dSStefan Richter "PHY register address %d out of range\n", addr); 26328646821SStefan Richter return -1; 26428646821SStefan Richter } 26528646821SStefan Richter if (val > 0xff) { 2667429b17dSStefan Richter dev_err(&lynx->pci_device->dev, 2677429b17dSStefan Richter "PHY register value %d out of range\n", val); 26828646821SStefan Richter return -1; 26928646821SStefan Richter } 27028646821SStefan Richter reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | 27128646821SStefan Richter LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); 27228646821SStefan Richter 27328646821SStefan Richter return 0; 27428646821SStefan Richter } 27528646821SStefan Richter 27628646821SStefan Richter static int 27728646821SStefan Richter nosy_open(struct inode *inode, struct file *file) 27828646821SStefan Richter { 27928646821SStefan Richter int minor = iminor(inode); 28055e77c06SStefan Richter struct client *client; 281424d66ceSStefan Richter struct pcilynx *tmp, *lynx = NULL; 28228646821SStefan Richter 283424d66ceSStefan Richter mutex_lock(&card_mutex); 284424d66ceSStefan Richter list_for_each_entry(tmp, &card_list, link) 285424d66ceSStefan Richter if (tmp->misc.minor == minor) { 286424d66ceSStefan Richter lynx = lynx_get(tmp); 287424d66ceSStefan Richter break; 288424d66ceSStefan Richter } 289424d66ceSStefan Richter mutex_unlock(&card_mutex); 290424d66ceSStefan Richter if (lynx == NULL) 29128646821SStefan Richter return -ENODEV; 29228646821SStefan Richter 29355e77c06SStefan Richter client = kmalloc(sizeof *client, GFP_KERNEL); 29455e77c06SStefan Richter if (client == NULL) 295424d66ceSStefan Richter goto fail; 29655e77c06SStefan Richter 29755e77c06SStefan Richter client->tcode_mask = ~0; 298424d66ceSStefan Richter client->lynx = lynx; 29955e77c06SStefan Richter INIT_LIST_HEAD(&client->link); 30055e77c06SStefan Richter 301424d66ceSStefan Richter if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) 302424d66ceSStefan Richter goto fail; 30355e77c06SStefan Richter 30455e77c06SStefan Richter file->private_data = client; 30555e77c06SStefan Richter 30660a74a6fSStefan Richter return nonseekable_open(inode, file); 307424d66ceSStefan Richter fail: 308424d66ceSStefan Richter kfree(client); 309424d66ceSStefan Richter lynx_put(lynx); 310424d66ceSStefan Richter 311424d66ceSStefan Richter return -ENOMEM; 31228646821SStefan Richter } 31328646821SStefan Richter 31428646821SStefan Richter static int 31528646821SStefan Richter nosy_release(struct inode *inode, struct file *file) 31628646821SStefan Richter { 31755e77c06SStefan Richter struct client *client = file->private_data; 318424d66ceSStefan Richter struct pcilynx *lynx = client->lynx; 31955e77c06SStefan Richter 320424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 32155e77c06SStefan Richter list_del_init(&client->link); 322424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 32355e77c06SStefan Richter 32455e77c06SStefan Richter packet_buffer_destroy(&client->buffer); 32555e77c06SStefan Richter kfree(client); 326424d66ceSStefan Richter lynx_put(lynx); 32728646821SStefan Richter 32828646821SStefan Richter return 0; 32928646821SStefan Richter } 33028646821SStefan Richter 331afc9a42bSAl Viro static __poll_t 33228646821SStefan Richter nosy_poll(struct file *file, poll_table *pt) 33328646821SStefan Richter { 33428646821SStefan Richter struct client *client = file->private_data; 335afc9a42bSAl Viro __poll_t ret = 0; 33628646821SStefan Richter 33728646821SStefan Richter poll_wait(file, &client->buffer.wait, pt); 33828646821SStefan Richter 33928646821SStefan Richter if (atomic_read(&client->buffer.size) > 0) 340424d66ceSStefan Richter ret = POLLIN | POLLRDNORM; 341424d66ceSStefan Richter 342424d66ceSStefan Richter if (list_empty(&client->lynx->link)) 343424d66ceSStefan Richter ret |= POLLHUP; 344424d66ceSStefan Richter 345424d66ceSStefan Richter return ret; 34628646821SStefan Richter } 34728646821SStefan Richter 34828646821SStefan Richter static ssize_t 349c89db7b8SStefan Richter nosy_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) 35028646821SStefan Richter { 35128646821SStefan Richter struct client *client = file->private_data; 35228646821SStefan Richter 353424d66ceSStefan Richter return packet_buffer_get(client, buffer, count); 35428646821SStefan Richter } 35528646821SStefan Richter 356c7b2a99cSStefan Richter static long 357c7b2a99cSStefan Richter nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 35828646821SStefan Richter { 35928646821SStefan Richter struct client *client = file->private_data; 360c7b2a99cSStefan Richter spinlock_t *client_list_lock = &client->lynx->client_list_lock; 36128646821SStefan Richter struct nosy_stats stats; 36228646821SStefan Richter 363b5e47729SStefan Richter switch (cmd) { 364b5e47729SStefan Richter case NOSY_IOC_GET_STATS: 365c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 36628646821SStefan Richter stats.total_packet_count = client->buffer.total_packet_count; 36728646821SStefan Richter stats.lost_packet_count = client->buffer.lost_packet_count; 368c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 369c7b2a99cSStefan Richter 370c89db7b8SStefan Richter if (copy_to_user((void __user *) arg, &stats, sizeof stats)) 37128646821SStefan Richter return -EFAULT; 37228646821SStefan Richter else 37328646821SStefan Richter return 0; 37428646821SStefan Richter 37528646821SStefan Richter case NOSY_IOC_START: 37655e77c06SStefan Richter spin_lock_irq(client_list_lock); 37755e77c06SStefan Richter list_add_tail(&client->link, &client->lynx->client_list); 37855e77c06SStefan Richter spin_unlock_irq(client_list_lock); 37955e77c06SStefan Richter 38028646821SStefan Richter return 0; 38128646821SStefan Richter 38228646821SStefan Richter case NOSY_IOC_STOP: 38355e77c06SStefan Richter spin_lock_irq(client_list_lock); 38455e77c06SStefan Richter list_del_init(&client->link); 38555e77c06SStefan Richter spin_unlock_irq(client_list_lock); 38655e77c06SStefan Richter 38728646821SStefan Richter return 0; 38828646821SStefan Richter 38928646821SStefan Richter case NOSY_IOC_FILTER: 390c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 39128646821SStefan Richter client->tcode_mask = arg; 392c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 39355e77c06SStefan Richter 39428646821SStefan Richter return 0; 39528646821SStefan Richter 39628646821SStefan Richter default: 39728646821SStefan Richter return -EINVAL; 39828646821SStefan Richter /* Flush buffer, configure filter. */ 39928646821SStefan Richter } 40028646821SStefan Richter } 40128646821SStefan Richter 402b5e47729SStefan Richter static const struct file_operations nosy_ops = { 40328646821SStefan Richter .owner = THIS_MODULE, 40428646821SStefan Richter .read = nosy_read, 405c7b2a99cSStefan Richter .unlocked_ioctl = nosy_ioctl, 40628646821SStefan Richter .poll = nosy_poll, 40728646821SStefan Richter .open = nosy_open, 40828646821SStefan Richter .release = nosy_release, 40928646821SStefan Richter }; 41028646821SStefan Richter 41128646821SStefan Richter #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 41228646821SStefan Richter 41328646821SStefan Richter static void 414685c3f80SStefan Richter packet_irq_handler(struct pcilynx *lynx) 41528646821SStefan Richter { 41628646821SStefan Richter struct client *client; 4172ae4b6b2SAmitoj Kaur Chawla u32 tcode_mask, tcode, timestamp; 41828646821SStefan Richter size_t length; 4192ae4b6b2SAmitoj Kaur Chawla struct timespec64 ts64; 42028646821SStefan Richter 42128646821SStefan Richter /* FIXME: Also report rcv_speed. */ 42228646821SStefan Richter 423fd8c8d46SStefan Richter length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff; 424fd8c8d46SStefan Richter tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf; 42528646821SStefan Richter 4262ae4b6b2SAmitoj Kaur Chawla ktime_get_real_ts64(&ts64); 4272ae4b6b2SAmitoj Kaur Chawla timestamp = ts64.tv_nsec / NSEC_PER_USEC; 4282ae4b6b2SAmitoj Kaur Chawla lynx->rcv_buffer[0] = (__force __le32)timestamp; 42928646821SStefan Richter 43028646821SStefan Richter if (length == PHY_PACKET_SIZE) 43128646821SStefan Richter tcode_mask = 1 << TCODE_PHY_PACKET; 43228646821SStefan Richter else 433fd8c8d46SStefan Richter tcode_mask = 1 << tcode; 43428646821SStefan Richter 435685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 43628646821SStefan Richter 437b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 43828646821SStefan Richter if (client->tcode_mask & tcode_mask) 43928646821SStefan Richter packet_buffer_put(&client->buffer, 44028646821SStefan Richter lynx->rcv_buffer, length + 4); 44128646821SStefan Richter 442685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 44328646821SStefan Richter } 44428646821SStefan Richter 44528646821SStefan Richter static void 446685c3f80SStefan Richter bus_reset_irq_handler(struct pcilynx *lynx) 44728646821SStefan Richter { 44828646821SStefan Richter struct client *client; 449384fbb96STina Ruchandani struct timespec64 ts64; 450384fbb96STina Ruchandani u32 timestamp; 45128646821SStefan Richter 452384fbb96STina Ruchandani ktime_get_real_ts64(&ts64); 453384fbb96STina Ruchandani timestamp = ts64.tv_nsec / NSEC_PER_USEC; 45428646821SStefan Richter 455685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 45628646821SStefan Richter 457b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 458384fbb96STina Ruchandani packet_buffer_put(&client->buffer, ×tamp, 4); 45928646821SStefan Richter 460685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 46128646821SStefan Richter } 46228646821SStefan Richter 46328646821SStefan Richter static irqreturn_t 46428646821SStefan Richter irq_handler(int irq, void *device) 46528646821SStefan Richter { 466b5e47729SStefan Richter struct pcilynx *lynx = device; 46728646821SStefan Richter u32 pci_int_status; 46828646821SStefan Richter 46928646821SStefan Richter pci_int_status = reg_read(lynx, PCI_INT_STATUS); 47028646821SStefan Richter 47116547667SStefan Richter if (pci_int_status == ~0) 47216547667SStefan Richter /* Card was ejected. */ 47316547667SStefan Richter return IRQ_NONE; 47416547667SStefan Richter 47528646821SStefan Richter if ((pci_int_status & PCI_INT_INT_PEND) == 0) 47628646821SStefan Richter /* Not our interrupt, bail out quickly. */ 47728646821SStefan Richter return IRQ_NONE; 47828646821SStefan Richter 47928646821SStefan Richter if ((pci_int_status & PCI_INT_P1394_INT) != 0) { 48028646821SStefan Richter u32 link_int_status; 48128646821SStefan Richter 48228646821SStefan Richter link_int_status = reg_read(lynx, LINK_INT_STATUS); 48328646821SStefan Richter reg_write(lynx, LINK_INT_STATUS, link_int_status); 48428646821SStefan Richter 48528646821SStefan Richter if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) 486685c3f80SStefan Richter bus_reset_irq_handler(lynx); 48728646821SStefan Richter } 48828646821SStefan Richter 48928646821SStefan Richter /* Clear the PCI_INT_STATUS register only after clearing the 49028646821SStefan Richter * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will 49128646821SStefan Richter * be set again immediately. */ 49228646821SStefan Richter 49328646821SStefan Richter reg_write(lynx, PCI_INT_STATUS, pci_int_status); 49428646821SStefan Richter 49528646821SStefan Richter if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { 496685c3f80SStefan Richter packet_irq_handler(lynx); 49728646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 49828646821SStefan Richter } 49928646821SStefan Richter 50028646821SStefan Richter return IRQ_HANDLED; 50128646821SStefan Richter } 50228646821SStefan Richter 50328646821SStefan Richter static void 50428646821SStefan Richter remove_card(struct pci_dev *dev) 50528646821SStefan Richter { 506424d66ceSStefan Richter struct pcilynx *lynx = pci_get_drvdata(dev); 507424d66ceSStefan Richter struct client *client; 50828646821SStefan Richter 509424d66ceSStefan Richter mutex_lock(&card_mutex); 510424d66ceSStefan Richter list_del_init(&lynx->link); 511424d66ceSStefan Richter misc_deregister(&lynx->misc); 512424d66ceSStefan Richter mutex_unlock(&card_mutex); 51328646821SStefan Richter 51428646821SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 51528646821SStefan Richter free_irq(lynx->pci_device->irq, lynx); 51628646821SStefan Richter 517424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 518424d66ceSStefan Richter list_for_each_entry(client, &lynx->client_list, link) 519424d66ceSStefan Richter wake_up_interruptible(&client->buffer.wait); 520424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 521424d66ceSStefan Richter 52228646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 52328646821SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 52428646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 52528646821SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 52628646821SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 52728646821SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 52828646821SStefan Richter 52928646821SStefan Richter iounmap(lynx->registers); 530b6d9c125SStefan Richter pci_disable_device(dev); 531424d66ceSStefan Richter lynx_put(lynx); 53228646821SStefan Richter } 53328646821SStefan Richter 53428646821SStefan Richter #define RCV_BUFFER_SIZE (16 * 1024) 53528646821SStefan Richter 53603f94c0fSBill Pemberton static int 53728646821SStefan Richter add_card(struct pci_dev *dev, const struct pci_device_id *unused) 53828646821SStefan Richter { 53928646821SStefan Richter struct pcilynx *lynx; 54028646821SStefan Richter u32 p, end; 541b6d9c125SStefan Richter int ret, i; 54228646821SStefan Richter 543e894d1d7Ssantosh nayak if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { 5447429b17dSStefan Richter dev_err(&dev->dev, 5457429b17dSStefan Richter "DMA address limits not supported for PCILynx hardware\n"); 546b5e47729SStefan Richter return -ENXIO; 547b5e47729SStefan Richter } 548b5e47729SStefan Richter if (pci_enable_device(dev)) { 5497429b17dSStefan Richter dev_err(&dev->dev, "Failed to enable PCILynx hardware\n"); 550b5e47729SStefan Richter return -ENXIO; 551b5e47729SStefan Richter } 55228646821SStefan Richter pci_set_master(dev); 55328646821SStefan Richter 55428646821SStefan Richter lynx = kzalloc(sizeof *lynx, GFP_KERNEL); 555b5e47729SStefan Richter if (lynx == NULL) { 5567429b17dSStefan Richter dev_err(&dev->dev, "Failed to allocate control structure\n"); 557b6d9c125SStefan Richter ret = -ENOMEM; 558b6d9c125SStefan Richter goto fail_disable; 559b5e47729SStefan Richter } 56028646821SStefan Richter lynx->pci_device = dev; 56128646821SStefan Richter pci_set_drvdata(dev, lynx); 56228646821SStefan Richter 56328646821SStefan Richter spin_lock_init(&lynx->client_list_lock); 56428646821SStefan Richter INIT_LIST_HEAD(&lynx->client_list); 565424d66ceSStefan Richter kref_init(&lynx->kref); 56628646821SStefan Richter 56728646821SStefan Richter lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), 56828646821SStefan Richter PCILYNX_MAX_REGISTER); 5696449e31dSAlexey Khoroshilov if (lynx->registers == NULL) { 5706449e31dSAlexey Khoroshilov dev_err(&dev->dev, "Failed to map registers\n"); 5716449e31dSAlexey Khoroshilov ret = -ENOMEM; 5726449e31dSAlexey Khoroshilov goto fail_deallocate_lynx; 5736449e31dSAlexey Khoroshilov } 57428646821SStefan Richter 57528646821SStefan Richter lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, 576b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_start_pcl_bus); 57728646821SStefan Richter lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, 578b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_pcl_bus); 579b5e47729SStefan Richter lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, 580b5e47729SStefan Richter RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); 58128646821SStefan Richter if (lynx->rcv_start_pcl == NULL || 58228646821SStefan Richter lynx->rcv_pcl == NULL || 583b5e47729SStefan Richter lynx->rcv_buffer == NULL) { 5847429b17dSStefan Richter dev_err(&dev->dev, "Failed to allocate receive buffer\n"); 585b6d9c125SStefan Richter ret = -ENOMEM; 5866449e31dSAlexey Khoroshilov goto fail_deallocate_buffers; 587b5e47729SStefan Richter } 588fd8c8d46SStefan Richter lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus); 589fd8c8d46SStefan Richter lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID); 590fd8c8d46SStefan Richter lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID); 59128646821SStefan Richter 59228646821SStefan Richter lynx->rcv_pcl->buffer[0].control = 593fd8c8d46SStefan Richter cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044); 594fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[0].pointer = 595fd8c8d46SStefan Richter cpu_to_le32(lynx->rcv_buffer_bus + 4); 59628646821SStefan Richter p = lynx->rcv_buffer_bus + 2048; 59728646821SStefan Richter end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 59828646821SStefan Richter for (i = 1; p < end; i++, p += 2048) { 59928646821SStefan Richter lynx->rcv_pcl->buffer[i].control = 600fd8c8d46SStefan Richter cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048); 601fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p); 60228646821SStefan Richter } 603fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF); 60428646821SStefan Richter 60528646821SStefan Richter reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 60628646821SStefan Richter /* Fix buggy cards with autoboot pin not tied low: */ 60728646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL, 0); 60828646821SStefan Richter reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); 60928646821SStefan Richter 61028646821SStefan Richter #if 0 61128646821SStefan Richter /* now, looking for PHY register set */ 61228646821SStefan Richter if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { 61328646821SStefan Richter lynx->phyic.reg_1394a = 1; 61428646821SStefan Richter PRINT(KERN_INFO, lynx->id, 61528646821SStefan Richter "found 1394a conform PHY (using extended register set)"); 61628646821SStefan Richter lynx->phyic.vendor = get_phy_vendorid(lynx); 61728646821SStefan Richter lynx->phyic.product = get_phy_productid(lynx); 61828646821SStefan Richter } else { 61928646821SStefan Richter lynx->phyic.reg_1394a = 0; 62028646821SStefan Richter PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); 62128646821SStefan Richter } 62228646821SStefan Richter #endif 62328646821SStefan Richter 62428646821SStefan Richter /* Setup the general receive FIFO max size. */ 62528646821SStefan Richter reg_write(lynx, FIFO_SIZES, 255); 62628646821SStefan Richter 62728646821SStefan Richter reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); 62828646821SStefan Richter 62928646821SStefan Richter reg_write(lynx, LINK_INT_ENABLE, 63028646821SStefan Richter LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | 63128646821SStefan Richter LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | 63228646821SStefan Richter LINK_INT_AT_STUCK | LINK_INT_SNTRJ | 63328646821SStefan Richter LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | 63428646821SStefan Richter LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); 63528646821SStefan Richter 63628646821SStefan Richter /* Disable the L flag in self ID packets. */ 63728646821SStefan Richter set_phy_reg(lynx, 4, 0); 63828646821SStefan Richter 63928646821SStefan Richter /* Put this baby into snoop mode */ 64028646821SStefan Richter reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); 64128646821SStefan Richter 64228646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 64328646821SStefan Richter 644b5e47729SStefan Richter if (request_irq(dev->irq, irq_handler, IRQF_SHARED, 645b5e47729SStefan Richter driver_name, lynx)) { 6467429b17dSStefan Richter dev_err(&dev->dev, 6477429b17dSStefan Richter "Failed to allocate shared interrupt %d\n", dev->irq); 648b6d9c125SStefan Richter ret = -EIO; 6496449e31dSAlexey Khoroshilov goto fail_deallocate_buffers; 650b5e47729SStefan Richter } 65128646821SStefan Richter 65228646821SStefan Richter lynx->misc.parent = &dev->dev; 65328646821SStefan Richter lynx->misc.minor = MISC_DYNAMIC_MINOR; 65428646821SStefan Richter lynx->misc.name = "nosy"; 65528646821SStefan Richter lynx->misc.fops = &nosy_ops; 656424d66ceSStefan Richter 657424d66ceSStefan Richter mutex_lock(&card_mutex); 658b6d9c125SStefan Richter ret = misc_register(&lynx->misc); 659b6d9c125SStefan Richter if (ret) { 6607429b17dSStefan Richter dev_err(&dev->dev, "Failed to register misc char device\n"); 661424d66ceSStefan Richter mutex_unlock(&card_mutex); 662b6d9c125SStefan Richter goto fail_free_irq; 663b5e47729SStefan Richter } 664424d66ceSStefan Richter list_add_tail(&lynx->link, &card_list); 665424d66ceSStefan Richter mutex_unlock(&card_mutex); 66628646821SStefan Richter 6677429b17dSStefan Richter dev_info(&dev->dev, 6687429b17dSStefan Richter "Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); 66928646821SStefan Richter 67028646821SStefan Richter return 0; 671b6d9c125SStefan Richter 672b6d9c125SStefan Richter fail_free_irq: 673b6d9c125SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 674b6d9c125SStefan Richter free_irq(lynx->pci_device->irq, lynx); 675b6d9c125SStefan Richter 6766449e31dSAlexey Khoroshilov fail_deallocate_buffers: 677b6d9c125SStefan Richter if (lynx->rcv_start_pcl) 678b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 679b6d9c125SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 680b6d9c125SStefan Richter if (lynx->rcv_pcl) 681b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 682b6d9c125SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 683b6d9c125SStefan Richter if (lynx->rcv_buffer) 684b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 685b6d9c125SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 686b6d9c125SStefan Richter iounmap(lynx->registers); 6876449e31dSAlexey Khoroshilov 6886449e31dSAlexey Khoroshilov fail_deallocate_lynx: 689b6d9c125SStefan Richter kfree(lynx); 690b6d9c125SStefan Richter 691b6d9c125SStefan Richter fail_disable: 692b6d9c125SStefan Richter pci_disable_device(dev); 693b6d9c125SStefan Richter 694b6d9c125SStefan Richter return ret; 69528646821SStefan Richter } 69628646821SStefan Richter 6977eeb7418SBill Pemberton static struct pci_device_id pci_table[] = { 69828646821SStefan Richter { 69928646821SStefan Richter .vendor = PCI_VENDOR_ID_TI, 70028646821SStefan Richter .device = PCI_DEVICE_ID_TI_PCILYNX, 70128646821SStefan Richter .subvendor = PCI_ANY_ID, 70228646821SStefan Richter .subdevice = PCI_ANY_ID, 70328646821SStefan Richter }, 70428646821SStefan Richter { } /* Terminating entry */ 70528646821SStefan Richter }; 70628646821SStefan Richter 707fe2af11cSAxel Lin MODULE_DEVICE_TABLE(pci, pci_table); 708fe2af11cSAxel Lin 70928646821SStefan Richter static struct pci_driver lynx_pci_driver = { 710b5e47729SStefan Richter .name = driver_name, 71128646821SStefan Richter .id_table = pci_table, 71228646821SStefan Richter .probe = add_card, 713b5e47729SStefan Richter .remove = remove_card, 71428646821SStefan Richter }; 71528646821SStefan Richter 716fe2af11cSAxel Lin module_pci_driver(lynx_pci_driver); 717fe2af11cSAxel Lin 718b5e47729SStefan Richter MODULE_AUTHOR("Kristian Hoegsberg"); 71928646821SStefan Richter MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); 72028646821SStefan Richter MODULE_LICENSE("GPL"); 721