Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) 2021-2022, Intel Corporation. */
0003 
0004 #include "ice.h"
0005 #include "ice_lib.h"
0006 #include <linux/tty_driver.h>
0007 
0008 /**
0009  * ice_gnss_do_write - Write data to internal GNSS
0010  * @pf: board private structure
0011  * @buf: command buffer
0012  * @size: command buffer size
0013  *
0014  * Write UBX command data to the GNSS receiver
0015  */
0016 static unsigned int
0017 ice_gnss_do_write(struct ice_pf *pf, unsigned char *buf, unsigned int size)
0018 {
0019     struct ice_aqc_link_topo_addr link_topo;
0020     struct ice_hw *hw = &pf->hw;
0021     unsigned int offset = 0;
0022     int err = 0;
0023 
0024     memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
0025     link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
0026     link_topo.topo_params.node_type_ctx |=
0027         FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
0028                ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE);
0029 
0030     /* It's not possible to write a single byte to u-blox.
0031      * Write all bytes in a loop until there are 6 or less bytes left. If
0032      * there are exactly 6 bytes left, the last write would be only a byte.
0033      * In this case, do 4+2 bytes writes instead of 5+1. Otherwise, do the
0034      * last 2 to 5 bytes write.
0035      */
0036     while (size - offset > ICE_GNSS_UBX_WRITE_BYTES + 1) {
0037         err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
0038                        cpu_to_le16(buf[offset]),
0039                        ICE_MAX_I2C_WRITE_BYTES,
0040                        &buf[offset + 1], NULL);
0041         if (err)
0042             goto err_out;
0043 
0044         offset += ICE_GNSS_UBX_WRITE_BYTES;
0045     }
0046 
0047     /* Single byte would be written. Write 4 bytes instead of 5. */
0048     if (size - offset == ICE_GNSS_UBX_WRITE_BYTES + 1) {
0049         err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
0050                        cpu_to_le16(buf[offset]),
0051                        ICE_MAX_I2C_WRITE_BYTES - 1,
0052                        &buf[offset + 1], NULL);
0053         if (err)
0054             goto err_out;
0055 
0056         offset += ICE_GNSS_UBX_WRITE_BYTES - 1;
0057     }
0058 
0059     /* Do the last write, 2 to 5 bytes. */
0060     err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
0061                    cpu_to_le16(buf[offset]), size - offset - 1,
0062                    &buf[offset + 1], NULL);
0063     if (err)
0064         goto err_out;
0065 
0066     return size;
0067 
0068 err_out:
0069     dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n",
0070         offset, size, err);
0071 
0072     return offset;
0073 }
0074 
0075 /**
0076  * ice_gnss_write_pending - Write all pending data to internal GNSS
0077  * @work: GNSS write work structure
0078  */
0079 static void ice_gnss_write_pending(struct kthread_work *work)
0080 {
0081     struct gnss_serial *gnss = container_of(work, struct gnss_serial,
0082                         write_work);
0083     struct ice_pf *pf = gnss->back;
0084 
0085     if (!list_empty(&gnss->queue)) {
0086         struct gnss_write_buf *write_buf = NULL;
0087         unsigned int bytes;
0088 
0089         write_buf = list_first_entry(&gnss->queue,
0090                          struct gnss_write_buf, queue);
0091 
0092         bytes = ice_gnss_do_write(pf, write_buf->buf, write_buf->size);
0093         dev_dbg(ice_pf_to_dev(pf), "%u bytes written to GNSS\n", bytes);
0094 
0095         list_del(&write_buf->queue);
0096         kfree(write_buf->buf);
0097         kfree(write_buf);
0098     }
0099 }
0100 
0101 /**
0102  * ice_gnss_read - Read data from internal GNSS module
0103  * @work: GNSS read work structure
0104  *
0105  * Read the data from internal GNSS receiver, number of bytes read will be
0106  * returned in *read_data parameter.
0107  */
0108 static void ice_gnss_read(struct kthread_work *work)
0109 {
0110     struct gnss_serial *gnss = container_of(work, struct gnss_serial,
0111                         read_work.work);
0112     struct ice_aqc_link_topo_addr link_topo;
0113     unsigned int i, bytes_read, data_len;
0114     struct tty_port *port;
0115     struct ice_pf *pf;
0116     struct ice_hw *hw;
0117     __be16 data_len_b;
0118     char *buf = NULL;
0119     u8 i2c_params;
0120     int err = 0;
0121 
0122     pf = gnss->back;
0123     if (!pf || !gnss->tty || !gnss->tty->port) {
0124         err = -EFAULT;
0125         goto exit;
0126     }
0127 
0128     hw = &pf->hw;
0129     port = gnss->tty->port;
0130 
0131     buf = (char *)get_zeroed_page(GFP_KERNEL);
0132     if (!buf) {
0133         err = -ENOMEM;
0134         goto exit;
0135     }
0136 
0137     memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
0138     link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
0139     link_topo.topo_params.node_type_ctx |=
0140         FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
0141                ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE);
0142 
0143     i2c_params = ICE_GNSS_UBX_DATA_LEN_WIDTH |
0144              ICE_AQC_I2C_USE_REPEATED_START;
0145 
0146     /* Read data length in a loop, when it's not 0 the data is ready */
0147     for (i = 0; i < ICE_MAX_UBX_READ_TRIES; i++) {
0148         err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
0149                       cpu_to_le16(ICE_GNSS_UBX_DATA_LEN_H),
0150                       i2c_params, (u8 *)&data_len_b, NULL);
0151         if (err)
0152             goto exit_buf;
0153 
0154         data_len = be16_to_cpu(data_len_b);
0155         if (data_len != 0 && data_len != U16_MAX)
0156             break;
0157 
0158         mdelay(10);
0159     }
0160 
0161     data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
0162     data_len = tty_buffer_request_room(port, data_len);
0163     if (!data_len) {
0164         err = -ENOMEM;
0165         goto exit_buf;
0166     }
0167 
0168     /* Read received data */
0169     for (i = 0; i < data_len; i += bytes_read) {
0170         unsigned int bytes_left = data_len - i;
0171 
0172         bytes_read = min_t(typeof(bytes_left), bytes_left,
0173                    ICE_MAX_I2C_DATA_SIZE);
0174 
0175         err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
0176                       cpu_to_le16(ICE_GNSS_UBX_EMPTY_DATA),
0177                       bytes_read, &buf[i], NULL);
0178         if (err)
0179             goto exit_buf;
0180     }
0181 
0182     /* Send the data to the tty layer for users to read. This doesn't
0183      * actually push the data through unless tty->low_latency is set.
0184      */
0185     tty_insert_flip_string(port, buf, i);
0186     tty_flip_buffer_push(port);
0187 
0188 exit_buf:
0189     free_page((unsigned long)buf);
0190     kthread_queue_delayed_work(gnss->kworker, &gnss->read_work,
0191                    ICE_GNSS_TIMER_DELAY_TIME);
0192 exit:
0193     if (err)
0194         dev_dbg(ice_pf_to_dev(pf), "GNSS failed to read err=%d\n", err);
0195 }
0196 
0197 /**
0198  * ice_gnss_struct_init - Initialize GNSS structure for the TTY
0199  * @pf: Board private structure
0200  * @index: TTY device index
0201  */
0202 static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf, int index)
0203 {
0204     struct device *dev = ice_pf_to_dev(pf);
0205     struct kthread_worker *kworker;
0206     struct gnss_serial *gnss;
0207 
0208     gnss = kzalloc(sizeof(*gnss), GFP_KERNEL);
0209     if (!gnss)
0210         return NULL;
0211 
0212     mutex_init(&gnss->gnss_mutex);
0213     gnss->open_count = 0;
0214     gnss->back = pf;
0215     pf->gnss_serial[index] = gnss;
0216 
0217     kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
0218     INIT_LIST_HEAD(&gnss->queue);
0219     kthread_init_work(&gnss->write_work, ice_gnss_write_pending);
0220     /* Allocate a kworker for handling work required for the GNSS TTY
0221      * writes.
0222      */
0223     kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev));
0224     if (IS_ERR(kworker)) {
0225         kfree(gnss);
0226         return NULL;
0227     }
0228 
0229     gnss->kworker = kworker;
0230 
0231     return gnss;
0232 }
0233 
0234 /**
0235  * ice_gnss_tty_open - Initialize GNSS structures on TTY device open
0236  * @tty: pointer to the tty_struct
0237  * @filp: pointer to the file
0238  *
0239  * This routine is mandatory. If this routine is not filled in, the attempted
0240  * open will fail with ENODEV.
0241  */
0242 static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp)
0243 {
0244     struct gnss_serial *gnss;
0245     struct ice_pf *pf;
0246 
0247     pf = (struct ice_pf *)tty->driver->driver_state;
0248     if (!pf)
0249         return -EFAULT;
0250 
0251     /* Clear the pointer in case something fails */
0252     tty->driver_data = NULL;
0253 
0254     /* Get the serial object associated with this tty pointer */
0255     gnss = pf->gnss_serial[tty->index];
0256     if (!gnss) {
0257         /* Initialize GNSS struct on the first device open */
0258         gnss = ice_gnss_struct_init(pf, tty->index);
0259         if (!gnss)
0260             return -ENOMEM;
0261     }
0262 
0263     mutex_lock(&gnss->gnss_mutex);
0264 
0265     /* Save our structure within the tty structure */
0266     tty->driver_data = gnss;
0267     gnss->tty = tty;
0268     gnss->open_count++;
0269     kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, 0);
0270 
0271     mutex_unlock(&gnss->gnss_mutex);
0272 
0273     return 0;
0274 }
0275 
0276 /**
0277  * ice_gnss_tty_close - Cleanup GNSS structures on tty device close
0278  * @tty: pointer to the tty_struct
0279  * @filp: pointer to the file
0280  */
0281 static void ice_gnss_tty_close(struct tty_struct *tty, struct file *filp)
0282 {
0283     struct gnss_serial *gnss = tty->driver_data;
0284     struct ice_pf *pf;
0285 
0286     if (!gnss)
0287         return;
0288 
0289     pf = (struct ice_pf *)tty->driver->driver_state;
0290     if (!pf)
0291         return;
0292 
0293     mutex_lock(&gnss->gnss_mutex);
0294 
0295     if (!gnss->open_count) {
0296         /* Port was never opened */
0297         dev_err(ice_pf_to_dev(pf), "GNSS port not opened\n");
0298         goto exit;
0299     }
0300 
0301     gnss->open_count--;
0302     if (gnss->open_count <= 0) {
0303         /* Port is in shutdown state */
0304         kthread_cancel_delayed_work_sync(&gnss->read_work);
0305     }
0306 exit:
0307     mutex_unlock(&gnss->gnss_mutex);
0308 }
0309 
0310 /**
0311  * ice_gnss_tty_write - Write GNSS data
0312  * @tty: pointer to the tty_struct
0313  * @buf: pointer to the user data
0314  * @count: the number of characters queued to be sent to the HW
0315  *
0316  * The write function call is called by the user when there is data to be sent
0317  * to the hardware. First the tty core receives the call, and then it passes the
0318  * data on to the tty driver's write function. The tty core also tells the tty
0319  * driver the size of the data being sent.
0320  * If any errors happen during the write call, a negative error value should be
0321  * returned instead of the number of characters queued to be written.
0322  */
0323 static int
0324 ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
0325 {
0326     struct gnss_write_buf *write_buf;
0327     struct gnss_serial *gnss;
0328     unsigned char *cmd_buf;
0329     struct ice_pf *pf;
0330     int err = count;
0331 
0332     /* We cannot write a single byte using our I2C implementation. */
0333     if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF)
0334         return -EINVAL;
0335 
0336     gnss = tty->driver_data;
0337     if (!gnss)
0338         return -EFAULT;
0339 
0340     pf = (struct ice_pf *)tty->driver->driver_state;
0341     if (!pf)
0342         return -EFAULT;
0343 
0344     /* Only allow to write on TTY 0 */
0345     if (gnss != pf->gnss_serial[0])
0346         return -EIO;
0347 
0348     mutex_lock(&gnss->gnss_mutex);
0349 
0350     if (!gnss->open_count) {
0351         err = -EINVAL;
0352         goto exit;
0353     }
0354 
0355     cmd_buf = kcalloc(count, sizeof(*buf), GFP_KERNEL);
0356     if (!cmd_buf) {
0357         err = -ENOMEM;
0358         goto exit;
0359     }
0360 
0361     memcpy(cmd_buf, buf, count);
0362 
0363     /* Send the data out to a hardware port */
0364     write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
0365     if (!write_buf) {
0366         err = -ENOMEM;
0367         goto exit;
0368     }
0369 
0370     write_buf->buf = cmd_buf;
0371     write_buf->size = count;
0372     INIT_LIST_HEAD(&write_buf->queue);
0373     list_add_tail(&write_buf->queue, &gnss->queue);
0374     kthread_queue_work(gnss->kworker, &gnss->write_work);
0375 exit:
0376     mutex_unlock(&gnss->gnss_mutex);
0377     return err;
0378 }
0379 
0380 /**
0381  * ice_gnss_tty_write_room - Returns the numbers of characters to be written.
0382  * @tty: pointer to the tty_struct
0383  *
0384  * This routine returns the numbers of characters the tty driver will accept
0385  * for queuing to be written or 0 if either the TTY is not open or user
0386  * tries to write to the TTY other than the first.
0387  */
0388 static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty)
0389 {
0390     struct gnss_serial *gnss = tty->driver_data;
0391 
0392     /* Only allow to write on TTY 0 */
0393     if (!gnss || gnss != gnss->back->gnss_serial[0])
0394         return 0;
0395 
0396     mutex_lock(&gnss->gnss_mutex);
0397 
0398     if (!gnss->open_count) {
0399         mutex_unlock(&gnss->gnss_mutex);
0400         return 0;
0401     }
0402 
0403     mutex_unlock(&gnss->gnss_mutex);
0404     return ICE_GNSS_TTY_WRITE_BUF;
0405 }
0406 
0407 static const struct tty_operations tty_gps_ops = {
0408     .open =     ice_gnss_tty_open,
0409     .close =    ice_gnss_tty_close,
0410     .write =    ice_gnss_tty_write,
0411     .write_room =   ice_gnss_tty_write_room,
0412 };
0413 
0414 /**
0415  * ice_gnss_create_tty_driver - Create a TTY driver for GNSS
0416  * @pf: Board private structure
0417  */
0418 static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
0419 {
0420     struct device *dev = ice_pf_to_dev(pf);
0421     const int ICE_TTYDRV_NAME_MAX = 14;
0422     struct tty_driver *tty_driver;
0423     char *ttydrv_name;
0424     unsigned int i;
0425     int err;
0426 
0427     tty_driver = tty_alloc_driver(ICE_GNSS_TTY_MINOR_DEVICES,
0428                       TTY_DRIVER_REAL_RAW);
0429     if (IS_ERR(tty_driver)) {
0430         dev_err(dev, "Failed to allocate memory for GNSS TTY\n");
0431         return NULL;
0432     }
0433 
0434     ttydrv_name = kzalloc(ICE_TTYDRV_NAME_MAX, GFP_KERNEL);
0435     if (!ttydrv_name) {
0436         tty_driver_kref_put(tty_driver);
0437         return NULL;
0438     }
0439 
0440     snprintf(ttydrv_name, ICE_TTYDRV_NAME_MAX, "ttyGNSS_%02x%02x_",
0441          (u8)pf->pdev->bus->number, (u8)PCI_SLOT(pf->pdev->devfn));
0442 
0443     /* Initialize the tty driver*/
0444     tty_driver->owner = THIS_MODULE;
0445     tty_driver->driver_name = dev_driver_string(dev);
0446     tty_driver->name = (const char *)ttydrv_name;
0447     tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
0448     tty_driver->subtype = SERIAL_TYPE_NORMAL;
0449     tty_driver->init_termios = tty_std_termios;
0450     tty_driver->init_termios.c_iflag &= ~INLCR;
0451     tty_driver->init_termios.c_iflag |= IGNCR;
0452     tty_driver->init_termios.c_oflag &= ~OPOST;
0453     tty_driver->init_termios.c_lflag &= ~ICANON;
0454     tty_driver->init_termios.c_cflag &= ~(CSIZE | CBAUD | CBAUDEX);
0455     /* baud rate 9600 */
0456     tty_termios_encode_baud_rate(&tty_driver->init_termios, 9600, 9600);
0457     tty_driver->driver_state = pf;
0458     tty_set_operations(tty_driver, &tty_gps_ops);
0459 
0460     for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
0461         pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
0462                            GFP_KERNEL);
0463         pf->gnss_serial[i] = NULL;
0464 
0465         tty_port_init(pf->gnss_tty_port[i]);
0466         tty_port_link_device(pf->gnss_tty_port[i], tty_driver, i);
0467     }
0468 
0469     err = tty_register_driver(tty_driver);
0470     if (err) {
0471         dev_err(dev, "Failed to register TTY driver err=%d\n", err);
0472 
0473         for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
0474             tty_port_destroy(pf->gnss_tty_port[i]);
0475             kfree(pf->gnss_tty_port[i]);
0476         }
0477         kfree(ttydrv_name);
0478         tty_driver_kref_put(pf->ice_gnss_tty_driver);
0479 
0480         return NULL;
0481     }
0482 
0483     for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
0484         dev_info(dev, "%s%d registered\n", ttydrv_name, i);
0485 
0486     return tty_driver;
0487 }
0488 
0489 /**
0490  * ice_gnss_init - Initialize GNSS TTY support
0491  * @pf: Board private structure
0492  */
0493 void ice_gnss_init(struct ice_pf *pf)
0494 {
0495     struct tty_driver *tty_driver;
0496 
0497     tty_driver = ice_gnss_create_tty_driver(pf);
0498     if (!tty_driver)
0499         return;
0500 
0501     pf->ice_gnss_tty_driver = tty_driver;
0502 
0503     set_bit(ICE_FLAG_GNSS, pf->flags);
0504     dev_info(ice_pf_to_dev(pf), "GNSS TTY init successful\n");
0505 }
0506 
0507 /**
0508  * ice_gnss_exit - Disable GNSS TTY support
0509  * @pf: Board private structure
0510  */
0511 void ice_gnss_exit(struct ice_pf *pf)
0512 {
0513     unsigned int i;
0514 
0515     if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver)
0516         return;
0517 
0518     for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
0519         if (pf->gnss_tty_port[i]) {
0520             tty_port_destroy(pf->gnss_tty_port[i]);
0521             kfree(pf->gnss_tty_port[i]);
0522         }
0523 
0524         if (pf->gnss_serial[i]) {
0525             struct gnss_serial *gnss = pf->gnss_serial[i];
0526 
0527             kthread_cancel_work_sync(&gnss->write_work);
0528             kthread_cancel_delayed_work_sync(&gnss->read_work);
0529             kfree(gnss);
0530             pf->gnss_serial[i] = NULL;
0531         }
0532     }
0533 
0534     tty_unregister_driver(pf->ice_gnss_tty_driver);
0535     kfree(pf->ice_gnss_tty_driver->name);
0536     tty_driver_kref_put(pf->ice_gnss_tty_driver);
0537     pf->ice_gnss_tty_driver = NULL;
0538 }
0539 
0540 /**
0541  * ice_gnss_is_gps_present - Check if GPS HW is present
0542  * @hw: pointer to HW struct
0543  */
0544 bool ice_gnss_is_gps_present(struct ice_hw *hw)
0545 {
0546     if (!hw->func_caps.ts_func_info.src_tmr_owned)
0547         return false;
0548 
0549 #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
0550     if (ice_is_e810t(hw)) {
0551         int err;
0552         u8 data;
0553 
0554         err = ice_read_pca9575_reg_e810t(hw, ICE_PCA9575_P0_IN, &data);
0555         if (err || !!(data & ICE_E810T_P0_GNSS_PRSNT_N))
0556             return false;
0557     } else {
0558         return false;
0559     }
0560 #else
0561     if (!ice_is_e810t(hw))
0562         return false;
0563 #endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
0564 
0565     return true;
0566 }